Project homepage Mailing List  Warmcat.com  API Docs  Github Mirror 
    npro  
 Modern all-safe Rust Network Protocol library supporting h1, h2, h3, ws, wt sans-IO and with socket IO + tls
git clone https://npro.rs/repo/npro
 
root / READMEs / README-resource-management.md
Author[]Andy Green <andy@warmcat.com> 2026-05-14 10:18 UTC
Committer[]Andy Green <andy@warmcat.com> 2026-05-15 07:55 UTC
Tree2f5f95b6db27d5b3e52388e8f231ee573f7bfc8a   Raw Patch
 
events: reflect step progress on task bg
events: reflect step progress on task bg
diff --git a/assets/404.html b/assets/404.html index 9d856c9..0da1a51 100644 --- a/assets/404.html +++ b/assets/404.html @@ -1,6 +1,8 @@ -<meta charset="UTF-8"> +<!DOCTYPE html> <html lang="en"> - <body> +<head> +<meta charset="UTF-8"> +</head> <img src="libwebsockets.org-logo.svg"><br> <h1>404</h1> Sorry, that file doesn't exist. diff --git a/assets/failed-login.html b/assets/failed-login.html index 66bfe9c..06f5d7a 100644 --- a/assets/failed-login.html +++ b/assets/failed-login.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> This is an example destination that will appear after a failed login </html> diff --git a/assets/gs/admin-login.html b/assets/gs/admin-login.html index fa36384..a6b2aef 100644 --- a/assets/gs/admin-login.html +++ b/assets/gs/admin-login.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> This is an example destination that will appear after successful Admin login. diff --git a/assets/gs/index.html b/assets/gs/index.html index a0445a0..5d33a6c 100644 --- a/assets/gs/index.html +++ b/assets/gs/index.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> diff --git a/assets/gs/post-forgot-fail.html b/assets/gs/post-forgot-fail.html index ed575a6..7666c94 100644 --- a/assets/gs/post-forgot-fail.html +++ b/assets/gs/post-forgot-fail.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> Sorry, something went wrong. diff --git a/assets/gs/post-forgot-ok.html b/assets/gs/post-forgot-ok.html index bfec1e0..27b0360 100644 --- a/assets/gs/post-forgot-ok.html +++ b/assets/gs/post-forgot-ok.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> This is a one-time password recovery login. diff --git a/assets/gs/post-verify-fail.html b/assets/gs/post-verify-fail.html index d0e5b3c..66e2975 100644 --- a/assets/gs/post-verify-fail.html +++ b/assets/gs/post-verify-fail.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> <head> <script src="lwsgs.js"></script> diff --git a/assets/gs/post-verify-ok.html b/assets/gs/post-verify-ok.html index 918b713..3d704d4 100644 --- a/assets/gs/post-verify-ok.html +++ b/assets/gs/post-verify-ok.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> <head> <script src="lwsgs.js"></script> diff --git a/assets/gs/sent-forgot-fail.html b/assets/gs/sent-forgot-fail.html index ed575a6..7666c94 100644 --- a/assets/gs/sent-forgot-fail.html +++ b/assets/gs/sent-forgot-fail.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> Sorry, something went wrong. diff --git a/assets/gs/successful-login.html b/assets/gs/successful-login.html index 39a47d5..f6ce3f2 100644 --- a/assets/gs/successful-login.html +++ b/assets/gs/successful-login.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> This is an example destination that will appear after successful non-Admin login </html> diff --git a/assets/index.html b/assets/index.html index 48ce7ea..ee8c0ec 100644 --- a/assets/index.html +++ b/assets/index.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> <head> <meta charset=utf-8 http-equiv="Content-Language" content="en"/> diff --git a/assets/post-register-ok.html b/assets/post-register-ok.html index b1bddd5..ba07895 100644 --- a/assets/post-register-ok.html +++ b/assets/post-register-ok.html @@ -1,3 +1,4 @@ +<!DOCTYPE html> <html lang="en"> <body> <table> diff --git a/assets/sai.css b/assets/sai.css index 9016e4b..ea28791 100644 --- a/assets/sai.css +++ b/assets/sai.css @@ -1179,10 +1179,10 @@ body.overlay-active { } .log-segment-wrapper { - margin-top: 4px; + margin: 2px 0; } .log-segment-body .log-segment-wrapper { - margin-left: 2em; + margin-left: 1em; } .log-segment-header { background-color: #f8f9fa; @@ -1192,8 +1192,7 @@ body.overlay-active { font-weight: bold; font-family: 'OpenSans', sans-serif; font-size: 11px; - margin-top: 1px; - margin-bottom: 1px; + margin: 0; user-select: none; -webkit-user-select: none; border-radius: 2px; @@ -1241,6 +1240,11 @@ body.overlay-active { width: 100%; border-collapse: collapse; table-layout: fixed; + margin: 0; + padding: 0; +} +.seg-header-table td { + padding: 0; } .seg-td-icon { @@ -1248,7 +1252,7 @@ body.overlay-active { text-align: center; } -.seg-td-lines, .seg-td-errors { +.seg-header-table .seg-td-lines, .seg-header-table .seg-td-errors { width: 100px; text-align: right; padding-right: 10px; @@ -1345,3 +1349,67 @@ canvas.power-graph { background: #ffdc00; color: black; } +.taskstate1.prog-0 { background: linear-gradient(90deg, #d0d0d0 0%, transparent 0%); } +.taskstate1.prog-5 { background: linear-gradient(90deg, #d0d0d0 5%, transparent 5%); } +.taskstate1.prog-10 { background: linear-gradient(90deg, #d0d0d0 10%, transparent 10%); } +.taskstate1.prog-15 { background: linear-gradient(90deg, #d0d0d0 15%, transparent 15%); } +.taskstate1.prog-20 { background: linear-gradient(90deg, #d0d0d0 20%, transparent 20%); } +.taskstate1.prog-25 { background: linear-gradient(90deg, #d0d0d0 25%, transparent 25%); } +.taskstate1.prog-30 { background: linear-gradient(90deg, #d0d0d0 30%, transparent 30%); } +.taskstate1.prog-35 { background: linear-gradient(90deg, #d0d0d0 35%, transparent 35%); } +.taskstate1.prog-40 { background: linear-gradient(90deg, #d0d0d0 40%, transparent 40%); } +.taskstate1.prog-45 { background: linear-gradient(90deg, #d0d0d0 45%, transparent 45%); } +.taskstate1.prog-50 { background: linear-gradient(90deg, #d0d0d0 50%, transparent 50%); } +.taskstate1.prog-55 { background: linear-gradient(90deg, #d0d0d0 55%, transparent 55%); } +.taskstate1.prog-60 { background: linear-gradient(90deg, #d0d0d0 60%, transparent 60%); } +.taskstate1.prog-65 { background: linear-gradient(90deg, #d0d0d0 65%, transparent 65%); } +.taskstate1.prog-70 { background: linear-gradient(90deg, #d0d0d0 70%, transparent 70%); } +.taskstate1.prog-75 { background: linear-gradient(90deg, #d0d0d0 75%, transparent 75%); } +.taskstate1.prog-80 { background: linear-gradient(90deg, #d0d0d0 80%, transparent 80%); } +.taskstate1.prog-85 { background: linear-gradient(90deg, #d0d0d0 85%, transparent 85%); } +.taskstate1.prog-90 { background: linear-gradient(90deg, #d0d0d0 90%, transparent 90%); } +.taskstate1.prog-95 { background: linear-gradient(90deg, #d0d0d0 95%, transparent 95%); } +.taskstate1.prog-100 { background: linear-gradient(90deg, #d0d0d0 100%, transparent 100%); } +.taskstate2.prog-0 { background: linear-gradient(90deg, #a0a0a0 0%, transparent 0%); } +.taskstate2.prog-5 { background: linear-gradient(90deg, #a0a0a0 5%, transparent 5%); } +.taskstate2.prog-10 { background: linear-gradient(90deg, #a0a0a0 10%, transparent 10%); } +.taskstate2.prog-15 { background: linear-gradient(90deg, #a0a0a0 15%, transparent 15%); } +.taskstate2.prog-20 { background: linear-gradient(90deg, #a0a0a0 20%, transparent 20%); } +.taskstate2.prog-25 { background: linear-gradient(90deg, #a0a0a0 25%, transparent 25%); } +.taskstate2.prog-30 { background: linear-gradient(90deg, #a0a0a0 30%, transparent 30%); } +.taskstate2.prog-35 { background: linear-gradient(90deg, #a0a0a0 35%, transparent 35%); } +.taskstate2.prog-40 { background: linear-gradient(90deg, #a0a0a0 40%, transparent 40%); } +.taskstate2.prog-45 { background: linear-gradient(90deg, #a0a0a0 45%, transparent 45%); } +.taskstate2.prog-50 { background: linear-gradient(90deg, #a0a0a0 50%, transparent 50%); } +.taskstate2.prog-55 { background: linear-gradient(90deg, #a0a0a0 55%, transparent 55%); } +.taskstate2.prog-60 { background: linear-gradient(90deg, #a0a0a0 60%, transparent 60%); } +.taskstate2.prog-65 { background: linear-gradient(90deg, #a0a0a0 65%, transparent 65%); } +.taskstate2.prog-70 { background: linear-gradient(90deg, #a0a0a0 70%, transparent 70%); } +.taskstate2.prog-75 { background: linear-gradient(90deg, #a0a0a0 75%, transparent 75%); } +.taskstate2.prog-80 { background: linear-gradient(90deg, #a0a0a0 80%, transparent 80%); } +.taskstate2.prog-85 { background: linear-gradient(90deg, #a0a0a0 85%, transparent 85%); } +.taskstate2.prog-90 { background: linear-gradient(90deg, #a0a0a0 90%, transparent 90%); } +.taskstate2.prog-95 { background: linear-gradient(90deg, #a0a0a0 95%, transparent 95%); } +.taskstate2.prog-100 { background: linear-gradient(90deg, #a0a0a0 100%, transparent 100%); } +.taskstate6.prog-0 { background: linear-gradient(90deg, #df3030 0%, transparent 0%); } +.taskstate6.prog-5 { background: linear-gradient(90deg, #df3030 5%, transparent 5%); } +.taskstate6.prog-10 { background: linear-gradient(90deg, #df3030 10%, transparent 10%); } +.taskstate6.prog-15 { background: linear-gradient(90deg, #df3030 15%, transparent 15%); } +.taskstate6.prog-20 { background: linear-gradient(90deg, #df3030 20%, transparent 20%); } +.taskstate6.prog-25 { background: linear-gradient(90deg, #df3030 25%, transparent 25%); } +.taskstate6.prog-30 { background: linear-gradient(90deg, #df3030 30%, transparent 30%); } +.taskstate6.prog-35 { background: linear-gradient(90deg, #df3030 35%, transparent 35%); } +.taskstate6.prog-40 { background: linear-gradient(90deg, #df3030 40%, transparent 40%); } +.taskstate6.prog-45 { background: linear-gradient(90deg, #df3030 45%, transparent 45%); } +.taskstate6.prog-50 { background: linear-gradient(90deg, #df3030 50%, transparent 50%); } +.taskstate6.prog-55 { background: linear-gradient(90deg, #df3030 55%, transparent 55%); } +.taskstate6.prog-60 { background: linear-gradient(90deg, #df3030 60%, transparent 60%); } +.taskstate6.prog-65 { background: linear-gradient(90deg, #df3030 65%, transparent 65%); } +.taskstate6.prog-70 { background: linear-gradient(90deg, #df3030 70%, transparent 70%); } +.taskstate6.prog-75 { background: linear-gradient(90deg, #df3030 75%, transparent 75%); } +.taskstate6.prog-80 { background: linear-gradient(90deg, #df3030 80%, transparent 80%); } +.taskstate6.prog-85 { background: linear-gradient(90deg, #df3030 85%, transparent 85%); } +.taskstate6.prog-90 { background: linear-gradient(90deg, #df3030 90%, transparent 90%); } +.taskstate6.prog-95 { background: linear-gradient(90deg, #df3030 95%, transparent 95%); } +.taskstate6.prog-100 { background: linear-gradient(90deg, #df3030 100%, transparent 100%); } + diff --git a/assets/sai.js b/assets/sai.js index 787c0aa..d73564c 100644 --- a/assets/sai.js +++ b/assets/sai.js @@ -612,13 +612,11 @@ function flush_segments() { } function append_chunk_table(id, chunk_index, target_dom) { - var html = ` - <table><tr> - <td class="atop"><div class="dlogsn" id="dlogsn-${id}-${chunk_index}"></div></td> - <td class="atop"><div class="dlogst" id="dlogst-${id}-${chunk_index}"></div></td> - <td class="atop"><div class="dlogs"><span class="nowrap" id="dlogs-${id}-${chunk_index}"></span></div></td> - </tr></table> - `; + var html = '<table><tr>' + + '<td class="atop"><div class="dlogsn" id="dlogsn-' + id + '-' + chunk_index + '"></div></td>' + + '<td class="atop"><div class="dlogst" id="dlogst-' + id + '-' + chunk_index + '"></div></td>' + + '<td class="atop"><div class="dlogs"><span class="nowrap" id="dlogs-' + id + '-' + chunk_index + '"></span></div></td>' + + '</tr></table>'; if (target_dom) target_dom.insertAdjacentHTML('beforeend', html); } @@ -627,7 +625,7 @@ function push_segment(title, default_folded) { seg_counter++; var id = seg_counter; - var seg = { id: id, title: title, lines_count: 0, error_count: 0, warning_count: 0, folded: default_folded, chunk_index: 0 }; + var seg = { id: id, title: title, lines_count: 0, error_count: 0, warning_count: 0, folded: default_folded, chunk_index: 0, auto_unfolded: false, user_toggled: false }; var parent_id = segment_stack.length > 0 ? segment_stack[segment_stack.length - 1].id : "root"; // Append to root's dlogs container OR the parent segment's BODY container @@ -639,18 +637,18 @@ function push_segment(title, default_folded) { var hideClass = default_folded ? " hide" : ""; var clean_title = title.replace(/^[\s\S]*?(?:>|&gt;)saib(?:>|&gt;)\s*/i, ''); - var html = `<div class="log-segment-wrapper"> - <div class="log-segment-header" id="hdr-seg-${id}"> - <table class="seg-header-table"><tr> - <td class="seg-td-icon"><span class="fold-icon">${icon}</span></td> - <td class="seg-td-lines"><span class="seg-lines">0</span> lines</td> - <td class="seg-td-errors"><span class="seg-errors"></span></td> - <td class="seg-td-title"><span class="seg-title">${hsanitize(clean_title)}</span></td> - </tr></table> - </div> - <div class="log-segment-body${hideClass}" id="seg-${id}"> - </div> - </div>`; + var html = '<div class="log-segment-wrapper">' + + '<div class="log-segment-header" id="hdr-seg-' + id + '">' + + '<table class="seg-header-table"><tr>' + + '<td class="seg-td-icon"><span class="fold-icon">' + icon + '</span></td>' + + '<td class="seg-td-lines"><span class="seg-lines">0</span> lines</td>' + + '<td class="seg-td-errors"><span class="seg-errors"></span></td>' + + '<td class="seg-td-title"><span class="seg-title">' + hsanitize(clean_title) + '</span></td>' + + '</tr></table>' + + '</div>' + + '<div class="log-segment-body' + hideClass + '" id="seg-' + id + '">' + + '</div>' + + '</div>'; // If root, we only append once, but wait, root is just flat. parent_dom.insertAdjacentHTML('beforeend', html); @@ -669,6 +667,20 @@ function push_segment(title, default_folded) { function pop_segment() { if (segment_stack.length > 0) { flush_segments(); + + var p = segment_stack[segment_stack.length - 1]; + if (p.auto_unfolded && p.error_count === 0 && !p.user_toggled) { + var body = document.getElementById("seg-" + p.id); + var hdr = document.getElementById("hdr-seg-" + p.id); + if (body && !body.classList.contains("hide")) { + body.classList.add("hide"); + if (hdr) { + var icon = hdr.querySelector('.fold-icon'); + if (icon) icon.innerText = "▶"; + } + } + } + segment_stack.pop(); // When we return to parent, we need a new table below the children we just popped @@ -682,6 +694,12 @@ function pop_segment() { } function toggleSegment(id) { + for (var i = 0; i < segment_stack.length; i++) { + if (segment_stack[i].id == id) { + segment_stack[i].user_toggled = true; + break; + } + } var body = document.getElementById("seg-" + id); var hdr = document.getElementById("hdr-seg-" + id); if (body && hdr) { @@ -1053,8 +1071,8 @@ function sai_taskinfo_render(t, now_ut) "id=\"stop-" + san(t.t.uuid) + "\">&nbsp;"; if (auth_is_admin) s += "<img class=\"rebuild\" alt=\"rebuild\" src=\"rebuild.png\" " + - "id=\"rebuild-" + san(t.t.uuid) + "\">&nbsp;" + - sai_stateful_taskname(t.t.state, t.t.taskname, 1); + "id=\"rebuild-" + san(t.t.uuid) + "\">&nbsp;"; + s += sai_stateful_taskname(t.t.state, t.t.taskname, 1); if (t.t.builder_name) { var now_ut = Math.round((new Date().getTime() / 1000)); @@ -1411,11 +1429,13 @@ function check_and_apply_failure_ui() { } } -function refresh_state(task_uuid, task_state) +function refresh_state(t) { - var tsi = document.getElementById("taskstate_" + task_uuid); + var task_uuid = t.uuid; + var task_state = t.state; + var els = document.querySelectorAll("[id='taskstate_" + task_uuid + "']"); - if (tsi) { + els.forEach(function(tsi) { tsi.classList.remove("taskstate0"); tsi.classList.remove("taskstate1"); tsi.classList.remove("taskstate2"); @@ -1426,8 +1446,26 @@ function refresh_state(task_uuid, task_state) tsi.classList.remove("taskstate7"); tsi.classList.remove("taskstate10"); tsi.classList.add("taskstate" + task_state); - // console.log("refresh_state taskstate" + task_state); - } + + var toRemove = []; + for (var i = 0; i < tsi.classList.length; i++) { + if (tsi.classList[i].startsWith('prog-')) { + toRemove.push(tsi.classList[i]); + } + } + toRemove.forEach(function(cls) { tsi.classList.remove(cls); }); + + if (task_state === 1 || task_state === 2 || task_state === 6) { + var total = typeof t.total_steps !== 'undefined' ? t.total_steps : t.build_step_count; + if (typeof t.build_step !== 'undefined' && typeof total !== 'undefined' && total >= 0) { + var pct = Math.round((t.build_step + 1) * 100 / (total + 2)); + if (pct > 100) pct = 100; + if (pct < 0) pct = 0; + pct = Math.round(pct / 5) * 5; + tsi.classList.add("prog-" + pct); + } + } + }); const urlParams = new URLSearchParams(window.location.search); const urlTask = urlParams.get('task'); @@ -2272,7 +2310,7 @@ function ws_open_sai() /* if the task status icons exist, update their state */ for (n = jso.overview[0].t.length - 1; n >= 0; n--) - refresh_state(jso.overview[0].t[n].uuid, jso.overview[0].t[n].state); + refresh_state(jso.overview[0].t[n]); update_summary_and_progress(jso.overview[0].e.uuid); @@ -2315,6 +2353,12 @@ function ws_open_sai() esr_el.innerHTML = sai_event_summary_render(jso.overview[n], now_ut, 1); + if (jso.overview[n].t) { + for (var q = 0; q < jso.overview[n].t.length; q++) { + refresh_state(jso.overview[n].t[q]); + } + } + update_summary_and_progress(jso.overview[n].e.uuid); } aging(); @@ -2416,7 +2460,7 @@ function ws_open_sai() if (document.getElementById("taskstate_" + jso.t.uuid)) { console.log("found taskstate_" + jso.t.uuid); - refresh_state(jso.t.uuid, jso.t.state); + refresh_state(jso.t); update_summary_and_progress(jso.t.uuid.substring(0, 32)); @@ -2868,6 +2912,22 @@ function ws_open_sai() rightPane.clientHeight <= rightPane.scrollTop + 1; + if (locked) { + for (var si = 0; si < segment_stack.length; si++) { + var sobj = segment_stack[si]; + var sdom = document.getElementById("seg-" + sobj.id); + var hdom = document.getElementById("hdr-seg-" + sobj.id); + if (sdom && sdom.classList.contains("hide")) { + sdom.classList.remove("hide"); + sobj.auto_unfolded = true; + if (hdom) { + var icon = hdom.querySelector('.fold-icon'); + if (icon) icon.innerText = "▼"; + } + } + } + } + flush_segments(); check_and_apply_failure_ui(); diff --git a/src/builder/b-power.c b/src/builder/b-power.c index beaae9b..077abd9 100644 --- a/src/builder/b-power.c +++ b/src/builder/b-power.c @@ -325,6 +325,7 @@ saib_power_link_rx(void *userobj, const uint8_t *buf, size_t len, int flags) if (memcmp(buf, "ACK:", 4)) { lwsl_warn("%s: sai-power didn't start power-off: %.*s\n", __func__, (int)len, (const char *)buf); + lws_sul_cancel(&builder.sul_do_shutdown); return LWSSSSRET_OK; } diff --git a/src/power/p-http-api.c b/src/power/p-http-api.c index 30d27d3..518b2a9 100644 --- a/src/power/p-http-api.c +++ b/src/power/p-http-api.c @@ -594,11 +594,13 @@ power_off: } lws_end_foreach_dll(px1); */ - if (needs[0] || (pc->flags & SAIP_PCON_F_NEEDED)) { + if (needs[0] || (pc->flags & SAIP_PCON_F_NEEDED) || + (pc->flags & SAIP_PCON_F_MANUAL_STAY)) { g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload), - "NAK: %s needed: %d, deps needed: '%s'", - pn, !!(pc->flags & SAIP_PCON_F_NEEDED), needs); + "NAK: %s needed: %d, stay: %d, deps needed: '%s'", + pn, !!(pc->flags & SAIP_PCON_F_NEEDED), + !!(pc->flags & SAIP_PCON_F_MANUAL_STAY), needs); goto bail; } } diff --git a/src/server/s-ws-builder.c b/src/server/s-ws-builder.c index 9d957b0..c1e6293 100644 --- a/src/server/s-ws-builder.c +++ b/src/server/s-ws-builder.c @@ -378,6 +378,8 @@ sais_set_builder_power_state(struct vhd *vhd, const char *name, int up, int down } } lws_end_foreach_dll_safe(p, p1); + ps = NULL; + lws_start_foreach_dll(struct lws_dll2 *, p, vhd->server.power_state_owner.head) { ps = lws_container_of(p, sai_power_state_t, list);
Page fetched 0s ago, creation time: 7ms (vhost etag hits: 0%, cache hits: 0%)