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
Author[]Andy Green <andy@warmcat.com> 2025-11-08 06:44 UTC
Committer[]Andy Green <andy@warmcat.com> 2025-11-09 09:19 UTC
Tree0d1dfc141321ed28e156e7810bdde4709ccad1ce   Raw Patch
 
Refresh of clean-reduce-indent-levels
Refresh of clean-reduce-indent-levels
diff --git a/assets/sai.css b/assets/sai.css index c3b8e64..b45379d 100644 --- a/assets/sai.css +++ b/assets/sai.css @@ -660,6 +660,11 @@ div.ibuil.power-stay { border: 2px solid green; } +div.ibuil.power-stay-dep { + border: 2px solid blue; +} + + div.ibuilctr { font-weight: normal; font-size: 9pt; @@ -811,6 +816,7 @@ img.branch { .context-menu { position: absolute; background-color: #f9f9f9; + font-size: 8pt; border: 1px solid #ccc; padding: 5px; z-index: 3000; diff --git a/assets/sai.js b/assets/sai.js index c0c6e72..94f7473 100644 --- a/assets/sai.js +++ b/assets/sai.js @@ -1030,8 +1030,10 @@ function createBuilderDiv(plat) { if (!plat.power_managed) platDiv.className += " power-unmanaged"; else - if (plat.stay_on) + if (plat.stay_on !== 0) platDiv.className += " power-stay"; + else + platDiv.className += " power-stay-dep"; } if (plat.powering_up) platDiv.className += " powering-up"; @@ -1055,7 +1057,7 @@ function createBuilderDiv(plat) { `<div class="res-bar"><div class="res-bar-inner res-bar-ram w-0"></div></div>` + `<div class="res-bar"><div class="res-bar-inner res-bar-disk w-0"></div></div>` + `</div>`; - innerHTML += `${plat.peer_ip}`; + innerHTML += `${plat.peer_ip}` + " " + plat.stay_on; // `<div class="server-state">` + // `Slots: ${plat.s_avail_slots}, In-flight: ${plat.s_inflight_count}<br>` + // `Last Reject: ${plat.s_last_rej_task_uuid ? plat.s_last_rej_task_uuid.substring(0, 8) : 'none'}` + "</div>" + @@ -1075,22 +1077,10 @@ function createBuilderDiv(plat) { const menuItems = [ { label: `<b>SAI:</b> ${plat.sai_hash}` }, { label: `<b>LWS:</b> ${plat.lws_hash}` }, - /* - { - label: "Update SAI", - callback: () => { - const rebuildMsg = { - schema: "com.warmcat.sai.rebuild", - builder_name: plat.name - }; - sai.send(JSON.stringify(rebuildMsg)); - } - } - */ ]; if (plat.power_managed && authd) { - if (plat.stay_on) { + if (plat.stay_on !== 0) { menuItems.push({ label: "Release Stay", callback: () => { diff --git a/src/builder/b-nspawn.c b/src/builder/b-nspawn.c index 33e58a1..43faa18 100644 --- a/src/builder/b-nspawn.c +++ b/src/builder/b-nspawn.c @@ -336,6 +336,7 @@ skip: saib_queue_task_status_update(ns->sp, ns->spm, ns->task->uuid, (unsigned int)ns->retcode, SAI_TASK_REASON_DESTROYED); + saib_reassess_idle_situation(); builder.ram_reserved_kib -= ns->task->est_peak_mem_kib; builder.disk_reserved_kib -= ns->task->est_disk_kib; @@ -361,6 +362,7 @@ fail: saib_queue_task_status_update(ns->sp, ns->spm, ns->task->uuid, (unsigned int)ns->retcode, SAI_TASK_REASON_DESTROYED); + saib_reassess_idle_situation(); builder.ram_reserved_kib -= ns->task->est_peak_mem_kib; builder.disk_reserved_kib -= ns->task->est_disk_kib; diff --git a/src/builder/b-power.c b/src/builder/b-power.c index 5238ac2..6d0f9f3 100644 --- a/src/builder/b-power.c +++ b/src/builder/b-power.c @@ -31,31 +31,11 @@ extern struct lws_spawn_piped *lsp_suspender; -/* - * This is used to check with sai-power if we should stay up (due to the power - * being turned on manually) - */ - - -LWS_SS_USER_TYPEDEF - char payload[200]; - size_t size; - size_t pos; -} saib_power_stay_t; - - -static lws_ss_state_return_t -saib_power_stay_rx(void *userobj, const uint8_t *buf, size_t len, int flags) +int +saib_reassess_idle_situation() { char in_use = 0; - if (len < 1) - return 0; - - builder.stay = *buf == '1'; - -// lwsl_err("%s: stay %d\n", __func__, builder.stay); - if (builder.stay) { /* * We need to deal with finding we have been manually powered-on. @@ -63,57 +43,86 @@ saib_power_stay_rx(void *userobj, const uint8_t *buf, size_t len, int flags) */ lws_sul_cancel(&builder.sul_idle); - // lwsl_warn("%s: %s: stay applied: cancelled idle grace time\n", - // __func__, builder.host); - } else { - - /* - * If any plat on this builder has tasks, just - * leave it - */ - lws_start_foreach_dll_safe(struct lws_dll2 *, mp, mp1, - builder.sai_plat_owner.head) { - struct sai_plat *sp = lws_container_of(mp, struct sai_plat, - sai_plat_list); + lwsl_warn("%s: %s: stay applied: cancelled idle grace time\n", + __func__, builder.host); - if (sp->nspawn_owner.head) { - lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, sp->nspawn_owner.head) { - struct sai_nspawn *xns = lws_container_of(d, struct sai_nspawn, list); + return 0; + } - lwsl_notice("%s: ongoing task: %s\n", __func__, xns->task->uuid); + /* + * If any plat on this builder has tasks, just leave it + */ + lws_start_foreach_dll_safe(struct lws_dll2 *, mp, mp1, + builder.sai_plat_owner.head) { + struct sai_plat *sp = lws_container_of(mp, struct sai_plat, + sai_plat_list); - } lws_end_foreach_dll_safe(d, d1); + if (sp->nspawn_owner.head) { + lws_start_foreach_dll_safe(struct lws_dll2 *, d, d1, + sp->nspawn_owner.head) { + struct sai_nspawn *xns = lws_container_of(d, + struct sai_nspawn, list); - in_use = 1; - } + lwsl_notice("%s: ongoing task: %s\n", __func__, + xns->task->uuid); - } lws_end_foreach_dll_safe(mp, mp1); + } lws_end_foreach_dll_safe(d, d1); - if (in_use) { - lwsl_warn("%s: cancelling idle grace time as ongoing task steps\n", __func__); lws_sul_cancel(&builder.sul_idle); - - return 0; + in_use = 1; } - /* - * if no ongoing tasks, and we want to go OFF, then start - * the idle grace timer. This will get cancelled if - * we start a task during the grace time, otherwise it will - * expire and do the power-off or suspend - */ - - if (lws_dll2_is_detached(&builder.sul_idle.list)) { - lwsl_warn("%s: %s: no stay: starting idle grace time\n", - __func__, builder.host); - lws_sul_schedule(builder.context, 0, &builder.sul_idle, - sul_idle_cb, SAI_IDLE_GRACE_US); - } + } lws_end_foreach_dll_safe(mp, mp1); + + if (in_use) { + lwsl_warn("%s: cancelling idle grace time as ongoing task steps\n", __func__); + + return 0; + } + + /* + * if no ongoing tasks, and we want to go OFF, then start + * the idle grace timer. This will get cancelled if + * we start a task during the grace time, otherwise it will + * expire and do the power-off or suspend + */ + + if (lws_dll2_is_detached(&builder.sul_idle.list)) { + lwsl_warn("%s: %s: no stay: starting idle grace time\n", + __func__, builder.host); + lws_sul_schedule(builder.context, 0, &builder.sul_idle, + sul_idle_cb, SAI_IDLE_GRACE_US); } return 0; } +/* + * This is used to check with sai-power if we should stay up (due to the power + * being turned on manually) + */ + + +LWS_SS_USER_TYPEDEF + char payload[200]; + size_t size; + size_t pos; +} saib_power_stay_t; + + +static lws_ss_state_return_t +saib_power_stay_rx(void *userobj, const uint8_t *buf, size_t len, int flags) +{ + if (len < 1) + return 0; + + builder.stay = *buf != '0'; + + saib_reassess_idle_situation(); + + return 0; +} + LWS_SS_INFO("sai_power", saib_power_stay_t) .rx = saib_power_stay_rx, }; @@ -352,6 +361,8 @@ saib_power_init(void) return 1; } + saib_reassess_idle_situation(); + return 0; } diff --git a/src/builder/b-private.h b/src/builder/b-private.h index 52b0426..d868c6c 100644 --- a/src/builder/b-private.h +++ b/src/builder/b-private.h @@ -330,6 +330,8 @@ extern int saib_deletion_init(const char *argv0); extern void suspender_destroy(void); +int +saib_reassess_idle_situation(void); #if defined(__APPLE__) int diff --git a/src/builder/b-suspender.c b/src/builder/b-suspender.c index d88cef7..4f7b60e 100644 --- a/src/builder/b-suspender.c +++ b/src/builder/b-suspender.c @@ -64,7 +64,7 @@ saib_suspender_get_pipe(void) #if defined(__linux__) int fd = lws_spawn_get_fd_stdxxx(lsp_suspender, 0); #else -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__NetBSD__) int fd = builder.pipe_suspender_wr; #else int fd = 2; @@ -172,7 +172,7 @@ saib_suspender_fork(const char *path) return 1; } #endif -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__NetBSD__) { int pfd[2]; pid_t pid; diff --git a/src/builder/b-task.c b/src/builder/b-task.c index d5e8d94..f26b948 100644 --- a/src/builder/b-task.c +++ b/src/builder/b-task.c @@ -721,6 +721,7 @@ saib_consider_allocating_task(struct sai_plat_server *spm, lws_struct_args_t *a, lwsl_warn("%s: server offered task that's already running\n", __func__); saib_queue_task_status_update(sp, spm, task->uuid, 0, SAI_TASK_REASON_DUPE); + saib_reassess_idle_situation(); return 0; } @@ -736,6 +737,7 @@ saib_consider_allocating_task(struct sai_plat_server *spm, lws_struct_args_t *a, if (saib_queue_task_status_update(sp, spm, task->uuid, 0, SAI_TASK_REASON_BUSY)) return -1; + saib_reassess_idle_situation(); return 0; } @@ -775,6 +777,7 @@ saib_consider_allocating_task(struct sai_plat_server *spm, lws_struct_args_t *a, lws_dll2_add_tail(&ns->list, &sp->nspawn_owner); + saib_reassess_idle_situation(); /* * If we're using sai-device, sort out the log proxy diff --git a/src/power/CMakeLists.txt b/src/power/CMakeLists.txt index 2842700..5942b29 100644 --- a/src/power/CMakeLists.txt +++ b/src/power/CMakeLists.txt @@ -7,6 +7,8 @@ set(SRCS p-comms.c p-smartplug.c p-api.c + p-utils.c + p-tasmota-monitor.c ../common/struct-metadata.c ) diff --git a/src/power/p-api.c b/src/power/p-api.c index d16c255..2dbde16 100644 --- a/src/power/p-api.c +++ b/src/power/p-api.c @@ -49,21 +49,24 @@ saip_sul_action_power_off(struct lws_sorted_usec_list *sul) { saip_server_plat_t *sp = lws_container_of(sul, saip_server_plat_t, sul_delay_off); + lws_ss_state_return_t r; + saip_pcon_t *pc; - if (!sp->power_off_url) { - lwsl_notice("%s: no power_off_url for %s\n", __func__, sp->host); - return; - } - if (!sp->ss_tasmota_off) { - lwsl_notice("%s: no power_off ss for %s\n", __func__, sp->host); + if (!sp->pcon_list.owner) { + lwsl_notice("%s: no power-controller ss for %s\n", __func__, sp->host); return; } - lwsl_warn("%s: powering off host %s\n", __func__, sp->host); + pc = lws_container_of(sp->pcon_list.owner, saip_pcon_t, + controlled_plats_owner); + saip_notify_server_power_state(sp->host, 0, 1); - if (lws_ss_client_connect(sp->ss_tasmota_off)) - lwsl_ss_err(sp->ss_tasmota_off, "failed to connect tasmota OFF secure stream"); + lwsl_warn("%s: powering OFF host %s via power-control %s\n", __func__, sp->host, pc->name); + + r = lws_ss_client_connect(pc->ss_tasmota_off); + if (r) + lwsl_ss_err(pc->ss_tasmota_off, "failed to connect tasmota OFF secure stream: %d", r); } saip_server_plat_t * @@ -87,8 +90,8 @@ find_platform(struct sai_power *pwr, const char *host) void saip_notify_server_stay_state(const char *plat_name, int stay_on) { - saip_server_t *sps; sai_stay_state_update_t *ssu; + saip_server_t *sps; /* Find the first (usually only) configured sai-server connection */ if (!power.sai_server_owner.head) { @@ -113,6 +116,7 @@ saip_notify_server_stay_state(const char *plat_name, int stay_on) /* The per-connection user object for the server link is a saip_server_link_t */ { saip_server_link_t *pss = (saip_server_link_t *)lws_ss_to_user_object(sps->ss); + lws_dll2_add_tail(&ssu->list, &pss->stay_state_update_owner); } @@ -133,28 +137,19 @@ saip_set_stay(const char *builder_name, int stay_on) if (!sp) return; + sps = lws_container_of(power.sai_server_owner.head, saip_server_t, list); + pss = (saip_server_link_t *)lws_ss_to_user_object(sps->ss); sp->stay = (char)stay_on; - saip_notify_server_stay_state(builder_name, stay_on); + saip_notify_server_stay_state(builder_name, stay_on | sp->needed); - if (stay_on) { - if (sp->power_on_mac) { - saip_notify_server_power_state(sp->host, 1, 0); - write(lws_spawn_get_fd_stdxxx(lsp_wol, 0), - sp->power_on_mac, strlen(sp->power_on_mac)); - } - if (sp->power_on_url) { - if (lws_ss_client_connect(sp->ss_tasmota_on)) - lwsl_notice("%s: tasmota connect failed\n", __func__); - saip_notify_server_power_state(sp->host, 1, 0); - } - } else { + if (stay_on | sp->needed) + saip_builder_bringup(sps, sp, pss); + else /* * power-off is delayed, so we just set the stay flag... * but let's cancel any pending power-off */ lws_sul_cancel(&sp->sul_delay_off); - } - /* Find the first (usually only) configured sai-server connection */ if (!power.sai_server_owner.head) { @@ -162,9 +157,6 @@ saip_set_stay(const char *builder_name, int stay_on) return; } - sps = lws_container_of(power.sai_server_owner.head, saip_server_t, list); - pss = (saip_server_link_t *)lws_ss_to_user_object(sps->ss); - saip_queue_stay_info(sps, sp, pss); } @@ -280,7 +272,7 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state, if (sp) g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload), - "%c", '0' + sp->stay); + "%c", '0' + (sp->stay | sp->needed)); else g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload), "unknown host %s", pn); @@ -308,16 +300,20 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state, sp->stay = 1; goto bail; } - if (!sp->power_on_url) { - g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload), - "no power-on-url entry for %s", pn); - goto bail; - } - if (lws_ss_client_connect(sp->ss_tasmota_on)) { - lwsl_ss_err(sp->ss_tasmota_off, "failed to connect tasmota ON secure stream"); + if (sp->pcon_list.owner) { + saip_pcon_t *pc = lws_container_of(sp->pcon_list.owner, + saip_pcon_t, + controlled_plats_owner); + if (lws_ss_client_connect(pc->ss_tasmota_on)) { + lwsl_ss_err(pc->ss_tasmota_on, "failed to connect tasmota ON secure stream"); + g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload), + "power-on ss failed create %s", sp->host); + goto bail; + } + } else { g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload), - "power-on ss failed create %s", sp->host); + "no power-controller entry for %s", pn); goto bail; } diff --git a/src/power/p-comms.c b/src/power/p-comms.c index 8508078..afd8fa0 100644 --- a/src/power/p-comms.c +++ b/src/power/p-comms.c @@ -107,20 +107,25 @@ saip_queue_stay_info(saip_server_t *sps, saip_server_plat_t *sp, saip_server_lin } int -saip_builder_bringup(saip_server_t *sps, saip_server_plat_t *sp, saip_server_link_t *pss) +saip_builder_bringup(saip_server_t *sps, saip_server_plat_t *sp, + saip_server_link_t *pss) { saip_notify_server_power_state(sp->name, 1, 0); - if (!strcmp(sp->power_on_type, "wol")) { + if (sp->power_on_type && !strcmp(sp->power_on_type, "wol")) { lwsl_notice("%s: triggering WOL\n", __func__); write(lws_spawn_get_fd_stdxxx(lsp_wol, 0), sp->power_on_mac, strlen(sp->power_on_mac)); } - if (!strcmp(sp->power_on_type, "tasmota")) { - lwsl_ss_notice(sp->ss_tasmota_on, "starting tasmota"); - if (lws_ss_client_connect(sp->ss_tasmota_on)) - lwsl_ss_err(sp->ss_tasmota_on, "failed to connect tasmota ON secure stream"); + if (sp->pcon_list.owner) { + saip_pcon_t *pc = lws_container_of(sp->pcon_list.owner, + saip_pcon_t, + controlled_plats_owner); + + lwsl_ss_notice(pc->ss_tasmota_on, "starting tasmota"); + if (lws_ss_client_connect(pc->ss_tasmota_on)) + lwsl_ss_err(pc->ss_tasmota_on, "failed to connect tasmota ON secure stream"); } return saip_queue_stay_info(sps, sp, pss); @@ -137,8 +142,8 @@ saip_m_rx(void *userobj, const uint8_t *buf, size_t len, int flags) lws_struct_args_t a; struct lejp_ctx ctx; - lwsl_info("%s: len %d, flags: %d (saip_server_t %p)\n", __func__, (int)len, flags, (void *)sps); - lwsl_hexdump_info(buf, len); + lwsl_notice("%s: len %d, flags: %d (saip_server_t %p)\n", __func__, (int)len, flags, (void *)sps); + lwsl_hexdump_notice(buf, len); memset(&a, 0, sizeof(a)); a.map_st[0] = lsm_schema_stay; @@ -149,6 +154,8 @@ saip_m_rx(void *userobj, const uint8_t *buf, size_t len, int flags) if (lejp_parse(&ctx, (uint8_t *)buf, (int)len) >= 0 && a.dest) { sai_stay_t *stay = (sai_stay_t *)a.dest; + // {"schema":"com.warmcat.sai.power.stay","builder_name":"ubuntu_rpi4","stay_on":1} + lwsl_warn("%s: received stay %s: %d\n", __func__, stay->builder_name, stay->stay_on); saip_set_stay(stay->builder_name, stay->stay_on); @@ -157,6 +164,8 @@ saip_m_rx(void *userobj, const uint8_t *buf, size_t len, int flags) } lwsac_free(&a.ac); + /* starting position is that no server-plat is needed */ + lws_start_foreach_dll(struct lws_dll2 *, px, sps->sai_plat_owner.head) { saip_server_plat_t *sp = lws_container_of(px, saip_server_plat_t, list); sp->needed = 0; @@ -189,10 +198,9 @@ saip_m_rx(void *userobj, const uint8_t *buf, size_t len, int flags) lws_start_foreach_dll(struct lws_dll2 *, px1, sp->dependencies_owner.head) { saip_server_plat_t *sp1 = lws_container_of(px1, saip_server_plat_t, dependencies_list); - if (!strcmp(sp1->name, plat)) { - sp->needed = 2; - break; - } + lwsl_notice("%s: setting %s as needed dep\n", __func__, sp1->name); + sp1->needed = 2; + saip_set_stay(sp1->name, sp1->stay); } lws_end_foreach_dll(px1); @@ -206,6 +214,27 @@ saip_m_rx(void *userobj, const uint8_t *buf, size_t len, int flags) } lws_end_foreach_dll(px); } + /* + * Cascade dependencies up the platforms + */ + + lws_start_foreach_dll(struct lws_dll2 *, px, sps->sai_plat_owner.head) { + saip_server_plat_t *sp = lws_container_of(px, saip_server_plat_t, list); + + if (sp->needed) { + lws_start_foreach_dll(struct lws_dll2 *, py, sp->dependencies_owner.head) { + saip_server_plat_t *spd = lws_container_of(py, saip_server_plat_t, dependencies_list); + + spd->needed |= 2; + + } lws_end_foreach_dll(py); + } + } lws_end_foreach_dll(px); + + /* + * Bringup any directly needed or needed by dependency builders + */ + lws_start_foreach_dll(struct lws_dll2 *, px, sps->sai_plat_owner.head) { saip_server_plat_t *sp = lws_container_of(px, saip_server_plat_t, list); @@ -252,7 +281,6 @@ saip_m_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len, if (!js) lwsl_ss_warn(lws_ss_from_user(pss), "Failed to serialize managed builder"); else - /* crashes here walking pmb */ if (lws_struct_json_serialize(js, buf, *len, len) == LSJS_RESULT_FINISH) *flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM; diff --git a/src/power/p-conf.c b/src/power/p-conf.c index 2cd50a6..11ffd96 100644 --- a/src/power/p-conf.c +++ b/src/power/p-conf.c @@ -33,6 +33,10 @@ static const char * const paths_global[] = { "perms", "wol-if", "servers[].url", + "servers[].power-control[].name", + "servers[].power-control[].type", + "servers[].power-control[].url", + "servers[].power-control[]", "servers[].platforms[].name", "servers[].platforms[].host", "servers[].platforms[].depends", @@ -43,6 +47,7 @@ static const char * const paths_global[] = { "servers[].platforms[].power-off.type", "servers[].platforms[].power-off.url", "servers[].platforms[].power-off", + "servers[].platforms[].power-control", "servers[].platforms[]", "servers[]" }; @@ -51,6 +56,10 @@ enum enum_paths_global { LEJPM_PERMS, LEJPM_WOL_IF, LEJPM_SERVERS_URL, + LEJPM_SERVERS_POWER_CONTROL_NAME, + LEJPM_SERVERS_POWER_CONTROL_TYPE, + LEJPM_SERVERS_POWER_CONTROL_URL, + LEJPM_SERVERS_POWER_CONTROL, LEJPM_SERVERS_PLATFORMS_NAME, LEJPM_SERVERS_PLATFORMS_HOST, LEJPM_SERVERS_PLATFORMS_DEPENDS, @@ -61,6 +70,7 @@ enum enum_paths_global { LEJPM_SERVERS_PLATFORMS_POWER_OFF_TYPE, LEJPM_SERVERS_PLATFORMS_POWER_OFF_URL, LEJPM_SERVERS_PLATFORMS_POWER_OFF, + LEJPM_SERVERS_PLATFORMS_POWER_CONTROL, LEJPM_SERVERS_PLATFORMS, LEJPM_SERVERS }; @@ -69,6 +79,7 @@ static signed char saip_conf_global_cb(struct lejp_ctx *ctx, char reason) { struct jpargs *a = (struct jpargs *)ctx->user; + saip_pcon_t *pc; const char **pp = NULL; #if 0 @@ -100,6 +111,18 @@ saip_conf_global_cb(struct lejp_ctx *ctx, char reason) &a->power->sai_server_owner); break; + case LEJPM_SERVERS_POWER_CONTROL: + /* + * Create the saip_pcon_t object and bind to the server + */ + a->sai_pcon = lwsac_use_zero(&a->power->ac_conf_head, + sizeof(*a->sai_pcon), 4096); + if (!a->sai_pcon) + return -1; + + lws_dll2_add_tail(&a->sai_pcon->list, + &a->power->sai_pcon_owner); + break; case LEJPM_SERVERS_PLATFORMS: /* @@ -138,6 +161,18 @@ saip_conf_global_cb(struct lejp_ctx *ctx, char reason) pp = &a->power->wol_if; break; + case LEJPM_SERVERS_POWER_CONTROL_NAME: + pp = &a->sai_pcon->name; + break; + + case LEJPM_SERVERS_POWER_CONTROL_TYPE: + pp = &a->sai_pcon->type; + break; + + case LEJPM_SERVERS_POWER_CONTROL_URL: + pp = &a->sai_pcon->url; + break; + case LEJPM_SERVERS_URL: pp = &a->sai_server->url; lwsl_user("%s: server url %.*s\n", __func__, ctx->npos, ctx->buf); @@ -175,6 +210,14 @@ saip_conf_global_cb(struct lejp_ctx *ctx, char reason) pp = &a->sai_server_plat->power_off_url; break; + case LEJPM_SERVERS_PLATFORMS_POWER_CONTROL: + pc = saip_pcon_by_name(a->power, ctx->buf); + if (pc) + lws_dll2_add_tail(&a->sai_server_plat->pcon_list, + &pc->controlled_plats_owner); + + return 0; + default: return 0; } diff --git a/src/power/p-private.h b/src/power/p-private.h index 822e39a..2388ddc 100644 --- a/src/power/p-private.h +++ b/src/power/p-private.h @@ -52,19 +52,53 @@ typedef enum { } cursor_phase_t; +typedef struct tasmota_data { + unsigned int voltage_v; + unsigned int current_ma; + unsigned int active_power_w; + unsigned int apparent_power_va; + unsigned int reactive_power_var; + unsigned int power_factor_scaled_1000; + unsigned int energy_today_wh; + unsigned int energy_yesterday_wh; + unsigned int energy_total_wh; +} tasmota_data_t; + +typedef struct tasmota_parse { + tasmota_data_t td; + struct lws_tokenize ts; + uint16_t match; + uint8_t s; +} tasmota_parse_t; + +typedef struct saip_pcon { + struct lws_dll2 list; + + lws_dll2_owner_t controlled_plats_owner; /* saip_server_plat_t */ + + const char *name; + const char *type; + const char *url; + char url_on[128]; + char url_off[128]; + char url_monitor[128]; + + struct lws_ss_handle *ss_tasmota_on; + struct lws_ss_handle *ss_tasmota_off; + struct lws_ss_handle *ss_tasmota_monitor; +} saip_pcon_t; struct saip_ws_pss; typedef struct saip_server_plat { - struct lws_dll2 list; - lws_dll2_owner_t dependencies_owner; + lws_dll2_t list; lws_dll2_t dependencies_list; + lws_dll2_t pcon_list; /* saip_pcon->controlled_plats_owner */ - lws_sorted_usec_list_t sul_delay_off; + lws_dll2_owner_t dependencies_owner; /* saip_server_plat_t->dependencies_list */ - struct lws_ss_handle *ss_tasmota_on; - struct lws_ss_handle *ss_tasmota_off; + lws_sorted_usec_list_t sul_delay_off; const char *name; const char *host; @@ -81,7 +115,7 @@ typedef struct saip_server_plat { } saip_server_plat_t; typedef struct saip_server { - struct lws_dll2 list; + lws_dll2_t list; lws_dll2_owner_t sai_plat_owner; /* list of platforms we offer */ @@ -98,6 +132,8 @@ typedef struct saip_server { struct sai_power { lws_dll2_owner_t sai_server_owner; /* servers we connect to */ + lws_dll2_owner_t sai_pcon_owner; /* saip_pcon_t */ + struct lwsac *ac_conf_head; struct lws_context *context; struct lws_vhost *vhost; @@ -125,6 +161,7 @@ struct jpargs { saip_server_t *sai_server; saip_server_plat_t *sai_server_plat; + saip_pcon_t *sai_pcon; sai_plat_server_ref_t *mref; @@ -158,4 +195,13 @@ saip_notify_server_power_state(const char *plat_name, int up, int down); void saip_set_stay(const char *builder_name, int stay_on); int -saip_queue_stay_info(saip_server_t *sps, saip_server_plat_t *sp, saip_server_link_t *pss); +saip_queue_stay_info(saip_server_t *sps, saip_server_plat_t *sp, + saip_server_link_t *pss); +saip_pcon_t * +saip_pcon_by_name(struct sai_power *power, const char *name); + +int +parse_tasmota_status(tasmota_parse_t *tp); +int +saip_builder_bringup(saip_server_t *sps, saip_server_plat_t *sp, + saip_server_link_t *pss); diff --git a/src/power/p-sai.c b/src/power/p-sai.c index cf9ee95..cab332a 100644 --- a/src/power/p-sai.c +++ b/src/power/p-sai.c @@ -369,26 +369,26 @@ int main(int argc, const char **argv) return 1; } - info.wol_if = power.wol_if; + info.wol_if = power.wol_if; if (power.wol_if) lwsl_notice("%s: WOL bound to interface %s\n", __func__, power.wol_if); info.pprotocols = pprotocols; //info.uid = 883; - info.pt_serv_buf_size = 32 * 1024; - info.rlimit_nofile = 20000; - info.options |= LWS_SERVER_OPTION_EXPLICIT_VHOSTS; + info.pt_serv_buf_size = 32 * 1024; + info.rlimit_nofile = 20000; + info.options |= LWS_SERVER_OPTION_EXPLICIT_VHOSTS; signal(SIGINT, sigint_handler); - info.pss_policies_json = default_ss_policy; - info.fd_limit_per_thread = 1 + 256 + 1; + info.pss_policies_json = default_ss_policy; + info.fd_limit_per_thread = 1 + 256 + 1; /* hook up our lws_system state notifier */ - nl.name = "sai-power"; - nl.notify_cb = app_system_state_nf; - info.register_notifier_list = app_notifier_list; + nl.name = "sai-power"; + nl.notify_cb = app_system_state_nf; + info.register_notifier_list = app_notifier_list; /* create the lws context */ @@ -406,25 +406,35 @@ int main(int argc, const char **argv) /* let's create any needed tasmota ss */ - lws_start_foreach_dll(struct lws_dll2 *, px, power.sai_server_owner.head) { - saip_server_t *s = lws_container_of(px, saip_server_t, list); - - lws_start_foreach_dll(struct lws_dll2 *, px1, s->sai_plat_owner.head) { - saip_server_plat_t *sp = lws_container_of(px1, saip_server_plat_t, list); - - if (!strcmp(sp->power_on_type, "tasmota") && sp->power_on_url && - lws_ss_create(power.context, 0, &ssi_saip_smartplug_t, - (void *)sp->power_on_url, &sp->ss_tasmota_on, NULL, NULL)) { - lwsl_err("%s: failed to create ON smartplug secure stream\n", __func__); - } - - if (!strcmp(sp->power_off_type, "tasmota") && sp->power_off_url && - lws_ss_create(power.context, 0, &ssi_saip_smartplug_t, - (void *)sp->power_off_url, &sp->ss_tasmota_off, NULL, NULL)) { - lwsl_err("%s: failed to create OFF smartplug secure stream\n", __func__); - } + lws_start_foreach_dll(struct lws_dll2 *, px, power.sai_pcon_owner.head) { + saip_pcon_t *pc = lws_container_of(px, saip_pcon_t, list); + + if (!strcmp(pc->type, "tasmota") && pc->url) { + lws_snprintf(pc->url_on, sizeof(pc->url_on), + "%s/cm?cmnd=Power%%20On", pc->url); + if (lws_ss_create(power.context, 0, &ssi_saip_smartplug_t, + (void *)pc->url_on, + &pc->ss_tasmota_on, NULL, NULL)) + lwsl_err("%s: %s: failed to create ON smartplug secure stream %s\n", + __func__, pc->name, pc->url_on); + + lws_snprintf(pc->url_off, sizeof(pc->url_off), + "%s/cm?cmnd=Power%%20Off", pc->url); + if (lws_ss_create(power.context, 0, &ssi_saip_smartplug_t, + (void *)pc->url_off, + &pc->ss_tasmota_off, NULL, NULL)) + lwsl_err("%s: %s: failed to create OFF smartplug secure stream %s\n", + __func__, pc->name, pc->url_off); + + lws_snprintf(pc->url_monitor, sizeof(pc->url_monitor), + "%s?m=1", pc->url); + if (lws_ss_create(power.context, 0, &ssi_saip_smartplug_t, + (void *)pc->url_monitor, + &pc->ss_tasmota_monitor, NULL, NULL)) + lwsl_err("%s: %s: failed to create MONITOR smartplug secure stream %s\n", + __func__, pc->name, pc->url_monitor); + } - } lws_end_foreach_dll(px1); } lws_end_foreach_dll(px); diff --git a/src/power/p-tasmota-monitor.c b/src/power/p-tasmota-monitor.c new file mode 100644 index 0000000..a6ebcad --- /dev/null +++ b/src/power/p-tasmota-monitor.c @@ -0,0 +1,156 @@ +/* + * sai-power com-warmcat-sai client protocol implementation + * + * Copyright (C) 2019 - 2025 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <libwebsockets.h> +#include <string.h> +#include <signal.h> + +#include "p-private.h" + +static const char *tokens[] = { + "Voltage", + "Current", + "Active", + "Power", + "Apparent", + "Reactive", + "Factor", + "Energy", + "Today", + "Yesterday", + "Total", +}; + +enum { + TOKORD_VOLTAGE, + TOKORD_CURRENT, + TOKORD_ACTIVE, + TOKORD_POWER, + TOKORD_APPARENT, + TOKORD_REACTIVE, + TOKORD_FACTOR, + TOKORD_ENERGY, + TOKORD_TODAY, + TOKORD_YESTERDAY, + TOKORD_TOTAL +}; + +int +parse_tasmota_status(tasmota_parse_t *tp) +{ + lws_tokenize_elem e; + unsigned int *i; + char *p; + int n; + + do { + e = lws_tokenize(&tp->ts); + + if (e == LWS_TOKZE_DELIMITER) { + switch (tp->ts.token[0]) { + case '<': + tp->s |= 1u; + break; + case '>': + tp->s &= (uint8_t)~1u; + continue; + case '{': + tp->s |= 2u; + break; + case '}': + tp->s &= (uint8_t)~2u; + continue; + case '&': + tp->s |= 4u; + break; + case ';': + tp->s &= (uint8_t)~4u; + continue; + } + } + + if (tp->s) + continue; + + switch (e) { + case LWS_TOKZE_ENDED: + return 1; + + case LWS_TOKZE_TOKEN: + for (n = 0; n < (int)LWS_ARRAY_SIZE(tokens); n++) { + if (strlen(tokens[n]) == tp->ts.token_len && + !strcmp(tokens[n], tp->ts.token)) { + tp->match = (uint16_t)((tp->match << 8) | n); + break; + } + } + + if (n == LWS_ARRAY_SIZE(tokens)) + continue; + break; + + case LWS_TOKZE_INTEGER: + if ((tp->match & 0xff) == TOKORD_VOLTAGE) + tp->td.voltage_v = (unsigned int)atoi(tp->ts.token); + if ((tp->match >> 8) == TOKORD_ACTIVE && (tp->match & 0xff) == TOKORD_POWER) + tp->td.active_power_w = (unsigned int)atoi(tp->ts.token); + if ((tp->match >> 8) == TOKORD_APPARENT && (tp->match & 0xff) == TOKORD_POWER) + tp->td.apparent_power_va = (unsigned int)atoi(tp->ts.token); + if ((tp->match >> 8) == TOKORD_REACTIVE && (tp->match & 0xff) == TOKORD_POWER) + tp->td.reactive_power_var = (unsigned int)atoi(tp->ts.token); + break; + + case LWS_TOKZE_FLOAT: + i = NULL; + + if ((tp->match & 0xff) == TOKORD_CURRENT) + i = &tp->td.current_ma; + if ((tp->match >> 8) == TOKORD_POWER && (tp->match & 0xff) == TOKORD_FACTOR) + i = &tp->td.power_factor_scaled_1000; + if ((tp->match >> 8) == TOKORD_ENERGY && (tp->match & 0xff) == TOKORD_TODAY) + i = &tp->td.energy_today_wh; + if ((tp->match >> 8) == TOKORD_ENERGY && (tp->match & 0xff) == TOKORD_YESTERDAY) + i = &tp->td.energy_yesterday_wh; + if ((tp->match >> 8) == TOKORD_ENERGY && (tp->match & 0xff) == TOKORD_TOTAL) + i = &tp->td.energy_total_wh; + + if (i) { + *i = 1000 * (unsigned int)atoi(tp->ts.token); + p = strchr(tp->ts.token, '.'); + if (p++) { + static const unsigned int mu[] = { 0, 100, 10, 1 }; + + n = (int)strlen(p); + if (n > 3) + n = 3; + *i += (unsigned int)atoi(p) * mu[n]; + } + } + break; + default: + break; + } + + } while (e > 0); + + return e; +} + diff --git a/src/power/p-utils.c b/src/power/p-utils.c new file mode 100644 index 0000000..6846dc8 --- /dev/null +++ b/src/power/p-utils.c @@ -0,0 +1,41 @@ +/* + * sai-power com-warmcat-sai client protocol implementation + * + * Copyright (C) 2019 - 2025 Andy Green <andy@warmcat.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation: + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#include <libwebsockets.h> +#include <string.h> +#include <signal.h> + +#include "p-private.h" + + +saip_pcon_t * +saip_pcon_by_name(struct sai_power *power, const char *name) +{ + lws_start_foreach_dll(struct lws_dll2 *, p, power->sai_pcon_owner.head) { + saip_pcon_t *pc = lws_container_of(p, saip_pcon_t, list); + + if (!strcmp(pc->name, name)) + return pc; + + } lws_end_foreach_dll(p); + + return NULL; +} diff --git a/src/server/s-comms.c b/src/server/s-comms.c index ee3f039..59a36ca 100644 --- a/src/server/s-comms.c +++ b/src/server/s-comms.c @@ -437,7 +437,6 @@ s_callback_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, if (!strcmp((char *)start, "/power")) { lwsl_notice("%s: ESTABLISHED: power connection\n", __func__); - pss->wsi = wsi; pss->is_power = 1; lws_dll2_add_head(&pss->same, &vhd->sai_powers); sais_platforms_with_tasks_pending(vhd); @@ -521,6 +520,12 @@ s_callback_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, break; } + if (pss->is_power || pss->stay_owner.head) { + lwsl_notice("%s: going down power tx path\n", __func__); + + return sais_power_tx(vhd, pss, buf, sizeof(buf)); + } + return sais_ws_json_tx_builder(vhd, pss, buf, sizeof(buf)); default: diff --git a/src/server/s-power.c b/src/server/s-power.c index b5c48c5..a941e3f 100644 --- a/src/server/s-power.c +++ b/src/server/s-power.c @@ -73,10 +73,13 @@ sais_power_rx(struct vhd *vhd, struct pss *pss, uint8_t *buf, switch (a.top_schema_index) { case 0: /* powerstate */ ps = (sai_power_state_t *)a.dest; + lwsl_notice("%s: powerstate received: %d %d\n", __func__, ps->powering_up, ps->powering_down); if (ps->powering_up) { lwsl_notice("sai-power is powering up: %s\n", ps->host); sais_set_builder_power_state(vhd, ps->host, 1, 0); - } else if (ps->powering_down) { + break; + } + if (ps->powering_down) { lwsl_notice("sai-power is powering down: %s\n", ps->host); sais_set_builder_power_state(vhd, ps->host, 0, 1); } @@ -150,9 +153,95 @@ sais_power_rx(struct vhd *vhd, struct pss *pss, uint8_t *buf, break; } + default: + lwsl_warn("%s: unknown schema\n", __func__); + break; } lwsac_free(&a.ac); return 0; } + +int +sais_power_tx(struct vhd *vhd, struct pss *pss, uint8_t *buf, size_t bl) +{ + uint8_t *start = buf + LWS_PRE, *p = start, *end = p + bl - LWS_PRE - 1; + enum lws_write_protocol flags; + char diff = 0; + size_t w; + int n; + + if (pss->stay_owner.head) { + /* + * Pending stay message to send to power + */ + sai_stay_t *s = lws_container_of(pss->stay_owner.head, + sai_stay_t, list); + lws_struct_serialize_t *js; + + js = lws_struct_json_serialize_create(lsm_schema_stay, + LWS_ARRAY_SIZE(lsm_schema_stay), 0, s); + if (!js) { + lwsl_warn("%s: failed to serialize stay\n", __func__); + return 1; + } + + n = (int)lws_struct_json_serialize(js, p, lws_ptr_diff_size_t(end, p), &w); + lws_struct_json_serialize_destroy(&js); + + lwsl_wsi_notice(pss->wsi, "%s: server issuing stay notice\n", __func__); + sai_dump_stderr((char *)start, w); + + lws_dll2_remove(&s->list); + free(s); + + flags = lws_write_ws_flags(LWS_WRITE_TEXT, 1, 1); + + if (lws_write(pss->wsi, start, w, flags) < 0) + return -1; + + lws_callback_on_writable(pss->wsi); + return 0; + } + + n = 0; + lws_start_foreach_dll(struct lws_dll2 *, px, vhd->pending_plats.head) { + sais_plat_t *pl = lws_container_of(px, sais_plat_t, list); + size_t m; + + if (n) + *p++ = ','; + m = strlen(pl->plat); + if (lws_ptr_diff_size_t(end, p) < m + 2) + break; + memcpy(p, pl->plat, m); + p += m; + *p = '\0'; + n = 1; + + } lws_end_foreach_dll(px); + + /* + * Don't resend the same status over and over + */ + + if (strncmp(pss->last_power_report, (const char *)start, lws_ptr_diff_size_t(p, start) + 1)) { + diff = 1; + memcpy(pss->last_power_report, start, lws_ptr_diff_size_t(p, start) + 1); + } + + if (diff /* && start != p */) { + lwsl_notice("%s: detected jobs for %.*s\n", __func__, + (int)lws_ptr_diff_size_t(p, start), start); + + if (lws_write(pss->wsi, start, lws_ptr_diff_size_t(p, start), + LWS_WRITE_TEXT) < 0) + return -1; + + lws_callback_on_writable(pss->wsi); + } + + return 0; +} + diff --git a/src/server/s-private.h b/src/server/s-private.h index 4b9d2c1..14f1a88 100644 --- a/src/server/s-private.h +++ b/src/server/s-private.h @@ -210,37 +210,37 @@ typedef struct sais_plat { } sais_plat_t; struct vhd { - struct lws_context *context; - struct lws_vhost *vhost; + struct lws_context *context; + struct lws_vhost *vhost; - struct lws_ss_handle *h_ss_websrv; /* server */ + sais_t server; + + struct lws_ss_handle *h_ss_websrv; /* server */ /* pss lists */ - struct lws_dll2_owner builders; - struct lws_dll2_owner sai_powers; - struct lws_dll2_owner pending_plats; - lws_dll2_owner_t powering_up_list; /* sai_powering_up_plat_t */ + struct lws_dll2_owner builders; + struct lws_dll2_owner sai_powers; + struct lws_dll2_owner pending_plats; + lws_dll2_owner_t powering_up_list; /* sai_powering_up_plat_t */ - struct lwsac *ac_plats; + struct lwsac *ac_plats; - const char *sqlite3_path_lhs; - sqlite3 *pdb_metrics; + const char *sqlite3_path_lhs; + sqlite3 *pdb_metrics; - lws_dll2_owner_t sqlite3_cache; /* sais_sqlite_cache_t */ - lws_dll2_owner_t tasklog_cache; - lws_sorted_usec_list_t sul_logcache; - lws_sorted_usec_list_t sul_central; /* background task allocation sul */ - lws_sorted_usec_list_t sul_activity; /* activity broadcast sul */ + lws_dll2_owner_t sqlite3_cache; /* sais_sqlite_cache_t */ + lws_dll2_owner_t tasklog_cache; + lws_sorted_usec_list_t sul_logcache; + lws_sorted_usec_list_t sul_central; /* background task allocation sul */ + lws_sorted_usec_list_t sul_activity; /* activity broadcast sul */ - lws_usec_t last_check_abandoned_tasks; + lws_usec_t last_check_abandoned_tasks; - const char *notification_key; - unsigned int task_abandoned_timeout_mins; + const char *notification_key; + unsigned int task_abandoned_timeout_mins; unsigned int browser_viewer_count; unsigned int viewers_are_present:1; - - sais_t server; }; extern struct lws_context * @@ -440,3 +440,6 @@ sais_metrics_db_init(struct vhd *vhd); int sais_metrics_db_prune(struct vhd *vhd, const char *key); + +int +sais_power_tx(struct vhd *vhd, struct pss *pss, uint8_t *buf, size_t bl); diff --git a/src/server/s-ws-builder.c b/src/server/s-ws-builder.c index 9657609..7f7c472 100644 --- a/src/server/s-ws-builder.c +++ b/src/server/s-ws-builder.c @@ -298,24 +298,33 @@ sais_set_builder_power_state(struct vhd *vhd, const char *name, int up, int down sai_power_state_t *ps = NULL; sai_plat_t *live_builder = sais_builder_from_host(vhd, name); - if (live_builder && up) + if (live_builder && up) { + lwsl_notice("%s: live builder so killing up\n", __func__); up = 0; + } - if (!live_builder && down) + if (!live_builder && down) { + lwsl_notice("%s: no live builder so killing down\n", __func__); down = 0; + } lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, vhd->server.power_state_owner.head) { ps = lws_container_of(p, sai_power_state_t, list); if (!strcmp(ps->host, name)) { - if (live_builder && ps->powering_up) + if (live_builder && ps->powering_up) { + lwsl_notice("%s: live builder so removing powering_up\n", __func__); ps->powering_up = 0; + } - if (!live_builder && ps->powering_down) + if (!live_builder && ps->powering_down) { + lwsl_notice("%s: no live builder so killing powering_down\n", __func__); ps->powering_down = 0; + } if (!ps->powering_up && !ps->powering_down) { + lwsl_notice("%s: nothing left to do for power state change, removing\n", __func__); lws_dll2_remove(&ps->list); free(ps); } @@ -345,7 +354,8 @@ sais_set_builder_power_state(struct vhd *vhd, const char *name, int up, int down if (!ps->powering_up && !ps->powering_down) { lws_dll2_remove(&ps->list); free(ps); - } + } else + lwsl_notice("%s: added ps with %d %d\n", __func__, up, down); } sais_list_builders(vhd); @@ -1358,27 +1368,6 @@ sais_ws_json_tx_builder(struct vhd *vhd, struct pss *pss, uint8_t *buf, goto send_json; } - if (pss->stay_owner.head) { - /* - * Pending stay message to send - */ - sai_stay_t *s = lws_container_of(pss->stay_owner.head, - sai_stay_t, list); - - js = lws_struct_json_serialize_create(lsm_schema_stay, - LWS_ARRAY_SIZE(lsm_schema_stay), 0, s); - if (!js) - return 1; - - n = (int)lws_struct_json_serialize(js, p, lws_ptr_diff_size_t(end, p), &w); - lws_struct_json_serialize_destroy(&js); - - lws_dll2_remove(&s->list); - free(s); - - goto send_json; - } - if (pss->rebuild_owner.head) { /* * Pending rebuild message to send @@ -1444,50 +1433,6 @@ sais_ws_json_tx_builder(struct vhd *vhd, struct pss *pss, uint8_t *buf, goto send_json; } - if (pss->is_power) { - char diff = 0; - - n = 0; - lws_start_foreach_dll(struct lws_dll2 *, px, vhd->pending_plats.head) { - sais_plat_t *pl = lws_container_of(px, sais_plat_t, list); - size_t m; - - if (n) - *p++ = ','; - m = strlen(pl->plat); - if (lws_ptr_diff_size_t(end, p) < m + 2) - break; - memcpy(p, pl->plat, m); - p += m; - *p = '\0'; - n = 1; - - } lws_end_foreach_dll(px); - - /* - * Don't resend the same status over and over - */ - - if (strncmp(pss->last_power_report, (const char *)start, lws_ptr_diff_size_t(p, start) + 1)) { - diff = 1; - memcpy(pss->last_power_report, start, lws_ptr_diff_size_t(p, start) + 1); - } - - if (diff && start != p) { - lwsl_notice("%s: detected jobs for %.*s\n", __func__, - (int)lws_ptr_diff_size_t(p, start), start); - - if (lws_write(pss->wsi, start, lws_ptr_diff_size_t(p, start), - LWS_WRITE_TEXT) < 0) - return -1; - - lws_callback_on_writable(pss->wsi); - - return 0; - } - } - - if (!pss->issue_task_owner.head) return 0; /* nothing to send */ diff --git a/src/server/s-ws-web.c b/src/server/s-ws-web.c index a4595a8..cdc2d90 100644 --- a/src/server/s-ws-web.c +++ b/src/server/s-ws-web.c @@ -194,10 +194,15 @@ sais_list_builders(struct vhd *vhd) lws_start_foreach_dll(struct lws_dll2 *, p, vhd->server.power_state_owner.head) { sai_power_state_t *ps = lws_container_of(p, sai_power_state_t, list); - size_t host_len = strlen(ps->host); + size_t host_len = strlen(ps->host), pl = strlen(builder_from_db->name); - if (!strncmp(builder_from_db->name, ps->host, host_len) && - builder_from_db->name[host_len] == '.') { + lwsl_notice("%s: %s vs %s\n", __func__, builder_from_db->name, ps->host); + + if ((!strncmp(builder_from_db->name, ps->host, host_len) && + builder_from_db->name[host_len] == '.') || (pl > host_len && + !strncmp(builder_from_db->name + (pl - host_len), ps->host, host_len))) + { + lwsl_notice("%s: adjusting powering_ %d %d\n", __func__, ps->powering_up, ps->powering_down); builder_from_db->powering_up = ps->powering_up; builder_from_db->powering_down = ps->powering_down; break; @@ -456,8 +461,10 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags) { sai_stay_t *stay = (sai_stay_t *)a.dest; + lwsl_notice("%s: stay received from web\n", __func__); + lws_start_foreach_dll(struct lws_dll2 *, p, - m->vhd->sai_powers.head) { + m->vhd->sai_powers.head) { struct pss *pss_power = lws_container_of(p, struct pss, same); sai_stay_t *s; @@ -466,6 +473,7 @@ websrvss_ws_rx(void *userobj, const uint8_t *buf, size_t len, int flags) *s = *stay; lws_dll2_add_tail(&s->list, &pss_power->stay_owner); lws_callback_on_writable(pss_power->wsi); + lwsl_wsi_notice(pss_power->wsi, "queued stay on power conn"); } } lws_end_foreach_dll(p); diff --git a/src/web/w-ws-browser.c b/src/web/w-ws-browser.c index 63bc32d..07b1397 100644 --- a/src/web/w-ws-browser.c +++ b/src/web/w-ws-browser.c @@ -518,8 +518,12 @@ saiw_ws_json_rx_browser(struct vhd *vhd, struct pss *pss, uint8_t *buf, break; case SAIM_WS_BROWSER_RX_STAY: - if (!sais_conn_auth(pss)) + if (!sais_conn_auth(pss)) { + lwsl_err("%s: stay didn't like auth\n", __func__); goto auth_error; + } + + lwsl_notice("%s: web: received stay req\n", __func__); /* * User is asking us to set or release a stay on a builder @@ -1224,14 +1228,12 @@ b_finish: * when we go out of scope... */ - lwsl_warn("%s: wwwwwwwwwwww PREPARE_TASKINFO: one_task %p\n", __func__, sch->one_task); - task_reply.event = sch->one_event; task_reply.task = sch->one_task; sch->one_task->rebuildable = (sch->one_task->state == SAIES_FAIL || sch->one_task->state == SAIES_CANCELLED) && (lws_now_secs() - (sch->one_task->started + - (sch->one_task->duration / 1000000)) < 24 * 3600); + (sch->one_task->duration / 1000000)) < 24 * 3600); task_reply.auth_secs = (int)(pss->authorized ? pss->expiry_unix_time - lws_now_secs() : 0); task_reply.authorized = pss->authorized; lws_strncpy(task_reply.auth_user, pss->auth_user, @@ -1306,9 +1308,7 @@ b_finish: return 0; } - lwsl_notice("%s: wwwwwwwwwww TASKINFO\n", __func__); - - sai_dump_stderr((const char *)start, lws_ptr_diff_size_t(p, start)); +// sai_dump_stderr((const char *)start, lws_ptr_diff_size_t(p, start)); break; case WSS_SEND_ARTIFACT_INFO:
Page fetched 0s ago, creation time: 32ms (vhost etag hits: 0%, cache hits: 0%)