mirror of
https://github.com/torlando-tech/pyxis.git
synced 2026-08-27 21:19:56 +00:00
fix: align NomadNet cache response policy
This commit is contained in:
@@ -124,6 +124,7 @@ NomadNetScreen::NomadNetScreen() {
|
||||
set_status("Enter a NomadNet address");show_start();hide();
|
||||
}
|
||||
NomadNetScreen::~NomadNetScreen(){
|
||||
cancel_status_timer();
|
||||
finish_field_edit(false);
|
||||
if(_field_editor)lv_textarea_set_text(_field_editor,"");
|
||||
if(_screen)lv_obj_del(_screen);
|
||||
@@ -382,11 +383,29 @@ void NomadNetScreen::set_address_editing(bool editing){
|
||||
else{lv_group_add_obj(group,_edit_button);lv_group_focus_obj(_edit_button);}
|
||||
}
|
||||
}
|
||||
void NomadNetScreen::cancel_status_timer(){
|
||||
if(!_status_timer)return;
|
||||
lv_timer_del(_status_timer);
|
||||
_status_timer=nullptr;
|
||||
}
|
||||
void NomadNetScreen::status_timer_cb(lv_timer_t* timer){
|
||||
auto* screen=static_cast<NomadNetScreen*>(timer->user_data);
|
||||
if(!screen||screen->_status_timer!=timer)return;
|
||||
screen->_status_timer=nullptr;
|
||||
screen->apply_browser_layout(false);
|
||||
}
|
||||
void NomadNetScreen::set_status(const char* value){
|
||||
cancel_status_timer();
|
||||
const char* status=value?value:"";
|
||||
lv_label_set_text(_status,status);
|
||||
const bool loaded_ack=_page_loaded&&std::strncmp(status,"Page loaded",11)==0;
|
||||
const bool cached_ack=_page_loaded&&std::strncmp(status,"Cached page",11)==0;
|
||||
apply_browser_layout(!loaded_ack);
|
||||
if(cached_ack){
|
||||
_status_timer=lv_timer_create(status_timer_cb,1500,this);
|
||||
if(_status_timer)lv_timer_set_repeat_count(_status_timer,1);
|
||||
else apply_browser_layout(false);
|
||||
}
|
||||
}
|
||||
bool NomadNetScreen::set_page(const NomadNet::Document& document) {
|
||||
// Prepare every heap-backed model before touching the published page. The
|
||||
|
||||
@@ -124,6 +124,7 @@ private:
|
||||
lv_obj_t* _reload_button=nullptr; lv_obj_t* _save_button=nullptr; lv_obj_t* _identify_button=nullptr; lv_obj_t* _address_row=nullptr; lv_obj_t* _address=nullptr;
|
||||
lv_obj_t* _go_button=nullptr; lv_obj_t* _address_summary=nullptr; lv_obj_t* _edit_button=nullptr;
|
||||
lv_obj_t* _status=nullptr; lv_obj_t* _content=nullptr; lv_obj_t* _field_editor=nullptr;
|
||||
lv_timer_t* _status_timer=nullptr;
|
||||
lv_obj_t* _directory=nullptr;
|
||||
NomadNet::CompactPage _page;
|
||||
NomadNet::FormState _form_state;
|
||||
@@ -159,6 +160,8 @@ private:
|
||||
Callback _back,_home; OpenCallback _reload,_open; LinkCallback _link;
|
||||
SubmitCallback _submit; SaveCallback _save; IdentifyCallback _identify;
|
||||
void set_address_editing(bool editing);
|
||||
static void status_timer_cb(lv_timer_t* timer);
|
||||
void cancel_status_timer();
|
||||
void apply_browser_layout(bool show_status);
|
||||
void render_directory(View view);
|
||||
void show_browser(bool editing);
|
||||
|
||||
@@ -2691,10 +2691,6 @@ void UIManager::nomad_update() {
|
||||
nomad_stop_transport();
|
||||
break;
|
||||
}
|
||||
const bool has_password = std::any_of(document.fields.begin(), document.fields.end(),
|
||||
[](const NomadNet::FormField& field) {
|
||||
return field.type == NomadNet::FormFieldType::PASSWORD;
|
||||
});
|
||||
const bool ordinary_nil =
|
||||
_nomad_request_data_class == NomadNet::RequestDataClass::NIL;
|
||||
const auto directive = NomadNet::parse_cache_directive(bytes.data(), bytes.size());
|
||||
@@ -2704,7 +2700,7 @@ void UIManager::nomad_update() {
|
||||
const NomadNet::CacheKey cache_key{
|
||||
_nomad_url.destination_hex, _nomad_url.path,
|
||||
_nomad_request_data_class};
|
||||
if (ordinary_nil && valid_document && !has_password && cache_now &&
|
||||
if (ordinary_nil && valid_document && cache_now &&
|
||||
directive.valid && directive.ttl) {
|
||||
_nomad_cache_pending_key = cache_key;
|
||||
_nomad_cache_pending_body = _nomad_response.take();
|
||||
@@ -2713,7 +2709,7 @@ void UIManager::nomad_update() {
|
||||
_nomad_cache_pending_generation = event.generation;
|
||||
} else {
|
||||
_nomad_response.release();
|
||||
if (ordinary_nil && (!directive.valid || directive.ttl == 0 || has_password))
|
||||
if (ordinary_nil && (!directive.valid || directive.ttl == 0))
|
||||
{ _nomad_cache_pending_key = cache_key;
|
||||
_nomad_cache_pending_generation = event.generation;
|
||||
_nomad_cache_pending_invalidate = true; }
|
||||
|
||||
@@ -34,5 +34,6 @@ target_include_directories(nomadnet_lvgl_acceptance PRIVATE
|
||||
target_compile_definitions(nomadnet_lvgl_acceptance PRIVATE ARDUINO=1)
|
||||
target_compile_options(nomadnet_lvgl_acceptance PRIVATE -Wall -Wextra
|
||||
-fsanitize=address,undefined -fno-omit-frame-pointer)
|
||||
target_link_options(nomadnet_lvgl_acceptance PRIVATE -fsanitize=address,undefined)
|
||||
target_link_options(nomadnet_lvgl_acceptance PRIVATE -fsanitize=address,undefined
|
||||
-Wl,--wrap=lv_timer_create)
|
||||
target_link_libraries(nomadnet_lvgl_acceptance PRIVATE lvgl)
|
||||
|
||||
@@ -23,6 +23,17 @@ lv_group_t* group = nullptr;
|
||||
lv_disp_t* display = nullptr;
|
||||
lv_indev_t* keyboard = nullptr;
|
||||
std::vector<lv_color_t> framebuffer(320 * 240);
|
||||
bool fail_next_timer_create = false;
|
||||
|
||||
extern "C" lv_timer_t* __real_lv_timer_create(lv_timer_cb_t, uint32_t, void*);
|
||||
extern "C" lv_timer_t* __wrap_lv_timer_create(lv_timer_cb_t callback, uint32_t period,
|
||||
void* user_data) {
|
||||
if (fail_next_timer_create) {
|
||||
fail_next_timer_create = false;
|
||||
return nullptr;
|
||||
}
|
||||
return __real_lv_timer_create(callback, period, user_data);
|
||||
}
|
||||
|
||||
struct KeyFeed { uint32_t key = 0; uint8_t phase = 0; } key_feed;
|
||||
|
||||
@@ -187,7 +198,8 @@ int main() {
|
||||
bool focus_events = false, edge_scroll = false;
|
||||
bool ready = false, cancel = false, enter = false, escape = false, focus_restore = false;
|
||||
bool table_pixels = false, form_pixels = false, focus_pixels = false, glyph_pixels = false;
|
||||
bool background_pixels = false, teardown = false;
|
||||
bool background_pixels = false, teardown = false, cached_status_transient = false;
|
||||
bool cached_status_oom_collapses = false;
|
||||
int delete_events = 0;
|
||||
|
||||
UI::LXMF::NomadNet::DocumentParser parser;
|
||||
@@ -200,6 +212,24 @@ int main() {
|
||||
"---\n`[Next`:/page/next.mu]\n`[Submit`:/page/form.mu`username]");
|
||||
assert(screen.set_page(fit_doc));
|
||||
lv_obj_update_layout(screen._screen);
|
||||
screen.set_status("Cached page; current reachability not checked");
|
||||
lv_obj_update_layout(screen._screen);
|
||||
const int16_t content_with_cached_notice = lv_obj_get_height(screen._content);
|
||||
const bool cached_notice_visible =
|
||||
!lv_obj_has_flag(screen._status, LV_OBJ_FLAG_HIDDEN);
|
||||
for (int i = 0; i < 12; ++i) pump();
|
||||
lv_obj_update_layout(screen._screen);
|
||||
cached_status_transient = cached_notice_visible &&
|
||||
lv_obj_has_flag(screen._status, LV_OBJ_FLAG_HIDDEN) &&
|
||||
lv_obj_get_height(screen._content) > content_with_cached_notice;
|
||||
screen.set_status("Checking page cache...");
|
||||
fail_next_timer_create = true;
|
||||
screen.set_status("Cached page; current reachability not checked");
|
||||
lv_obj_update_layout(screen._screen);
|
||||
cached_status_oom_collapses = !fail_next_timer_create &&
|
||||
screen._status_timer == nullptr &&
|
||||
lv_obj_has_flag(screen._status, LV_OBJ_FLAG_HIDDEN) &&
|
||||
lv_obj_get_height(screen._content) > content_with_cached_notice;
|
||||
const auto fit = screen._table_layout;
|
||||
fit_tier = fit.valid && fit.tier == UI::LXMF::NomadNet::TableLayoutTier::FIT;
|
||||
fit_columns = fit.columns == 2 && fit.cards == 0 && fit.x >= 0 && fit.width > 0 &&
|
||||
@@ -338,15 +368,17 @@ int main() {
|
||||
"LVGL ACCEPT 320x240 fit_tier=%d fit_columns=%d reflow_tier=%d reflow_cards=%d "
|
||||
"stacked_tier=%d stacked_cards=%d stacked_pixels=%d stacked_scroll=%d stacked_objects=%d "
|
||||
"focus_events=%d edge_scroll=%d ready=%d cancel=%d enter=%d escape=%d focus_restore=%d "
|
||||
"teardown=%d stale_group=%d background_pixels=%d table_pixels=%d form_pixels=%d "
|
||||
"teardown=%d cached_status_transient=%d cached_status_oom_collapses=%d stale_group=%d background_pixels=%d table_pixels=%d form_pixels=%d "
|
||||
"focus_pixels=%d glyph_pixels=%d exact_fonts=1 objects=%u\n",
|
||||
fit_tier, fit_columns, reflow_tier, reflow_cards, stacked_tier, stacked_cards,
|
||||
stacked_pixels, stacked_scroll, stacked_objects, focus_events, edge_scroll,
|
||||
ready, cancel, enter, escape, focus_restore, teardown, 0, background_pixels,
|
||||
ready, cancel, enter, escape, focus_restore, teardown, cached_status_transient,
|
||||
cached_status_oom_collapses, 0, background_pixels,
|
||||
table_pixels, form_pixels, focus_pixels, glyph_pixels, remaining);
|
||||
return fit_tier && fit_columns && reflow_tier && reflow_cards && stacked_tier &&
|
||||
stacked_cards && stacked_pixels && stacked_scroll && stacked_objects &&
|
||||
focus_events && edge_scroll &&
|
||||
ready && cancel && enter && escape && focus_restore && teardown && background_pixels &&
|
||||
ready && cancel && enter && escape && focus_restore && teardown && cached_status_transient &&
|
||||
cached_status_oom_collapses && background_pixels &&
|
||||
table_pixels && form_pixels && focus_pixels && glyph_pixels && remaining == 0 ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -1057,13 +1057,26 @@ def test_nomadnet_same_destination_navigation_reuses_active_link():
|
||||
"nomad_finish_request_keep_link();"
|
||||
)
|
||||
application_failure = response[response.index("if (!page_applied)"):
|
||||
response.index("const bool has_password")]
|
||||
response.index("const bool ordinary_nil")]
|
||||
assert "nomad_stop_transport();" in application_failure
|
||||
retained = response[response.index("_nomad_link.status() == Type::Link::ACTIVE"):]
|
||||
assert "_nomad_destination_hash.toHex() == _nomad_url.destination_hex" in retained
|
||||
assert "nomad_stop_transport();" in retained
|
||||
|
||||
|
||||
def test_nomadnet_cache_persists_only_unsubmitted_server_response_bodies():
|
||||
manager_cpp = (INCLUDE / "UIManager.cpp").read_text()
|
||||
response = manager_cpp[manager_cpp.index("case NomadNet::AsyncMailbox::Kind::RESPONSE:"):
|
||||
manager_cpp.index("case NomadNet::AsyncMailbox::Kind::NONE:")]
|
||||
|
||||
# A password descriptor in server markup does not contain mutable editor state.
|
||||
# Cache admission is based on the request-data class, not field descriptors.
|
||||
assert "has_password" not in response
|
||||
assert "_nomad_request_data_class == NomadNet::RequestDataClass::NIL" in response
|
||||
assert "ordinary_nil && valid_document && cache_now" in response
|
||||
assert "_nomad_cache_pending_body = _nomad_response.take();" in response
|
||||
|
||||
|
||||
def test_nomadnet_owner_routes_back_reload_and_table_observation_is_private():
|
||||
screen_h = (INCLUDE / "NomadNetScreen.h").read_text()
|
||||
manager_h = (INCLUDE / "UIManager.h").read_text()
|
||||
|
||||
@@ -41,7 +41,7 @@ def test_actual_nomadnet_screen_320x240_acceptance(tmp_path):
|
||||
assert "stacked_tier=1 stacked_cards=1 stacked_pixels=1 stacked_scroll=1 stacked_objects=1" in output
|
||||
assert "focus_events=1 edge_scroll=1" in output
|
||||
assert "ready=1 cancel=1 enter=1 escape=1 focus_restore=1" in output
|
||||
assert "teardown=1 stale_group=0" in output
|
||||
assert "teardown=1 cached_status_transient=1 cached_status_oom_collapses=1 stale_group=0" in output
|
||||
assert "background_pixels=1 table_pixels=1 form_pixels=1 focus_pixels=1 glyph_pixels=1" in output
|
||||
assert "exact_fonts=1" in output
|
||||
assert output.endswith("objects=0")
|
||||
|
||||
Reference in New Issue
Block a user