diff --git a/src/builder/b-sai.c b/src/builder/b-sai.c
index d944a98..ca4af05 100644
--- a/src/builder/b-sai.c
+++ b/src/builder/b-sai.c
@@ -547,7 +547,7 @@ LWS_SS_USER_TYPEDEF
} saib_power_link_t;
static lws_ss_state_return_t
-sai_power_link_state(void *userobj, void *sh, lws_ss_constate_t state,
+saib_power_link_state(void *userobj, void *sh, lws_ss_constate_t state,
lws_ss_tx_ordinal_t ack)
{
saib_power_link_t *g = (saib_power_link_t *)userobj;
@@ -558,7 +558,7 @@ sai_power_link_state(void *userobj, void *sh, lws_ss_constate_t state,
switch (state) {
case LWSSSCS_CREATING:
- snprintf(path, sizeof(path) - 1, "%s/power-off/%s",
+ snprintf(path, sizeof(path) - 1, "%s/auto-power-off/%s",
builder.url_sai_power,
(const char *)lws_ss_opaque_from_user(g));
@@ -568,7 +568,13 @@ sai_power_link_state(void *userobj, void *sh, lws_ss_constate_t state,
if (r)
lwsl_err("%s: set_metadata said %d\n", __func__, (int)r);
+ lws_ss_start_timeout(lws_ss_from_user(g), 3000); /* 3 sec */
+
return lws_ss_request_tx(lws_ss_from_user(g));
+
+ case LWSSSCS_TIMEOUT:
+ break;
+
default:
break;
}
@@ -576,8 +582,39 @@ sai_power_link_state(void *userobj, void *sh, lws_ss_constate_t state,
return LWSSSSRET_OK;
}
+static lws_ss_state_return_t
+saib_power_link_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+ uint8_t te = 0;
+ ssize_t n;
+
+ if (len < 4 || !(flags & LWSSS_FLAG_SOM))
+ return 0;
+
+ if (memcmp(buf, "ACK:", 4)) {
+ lwsl_warn("%s: sai-power didn't start power-off: %.*s\n",
+ __func__, (int)len, (const char *)buf);
+ return LWSSSSRET_OK;
+ }
+
+ lwsl_notice("%s: sai-power scheduling power-off: doing shutdown...\n", __func__);
+
+ /*
+ * In the grace time for actioning the power-off, we should shutdown
+ * cleanly
+ */
+
+ n = write(lws_spawn_get_fd_stdxxx(lsp_suspender, 0), &te, 1);
+ if (n != 1)
+ lwsl_err("%s: unable to request shutdown\n", __func__);
+
+ return LWSSSSRET_OK;
+}
+
+
LWS_SS_INFO("sai_power", saib_power_link_t)
- .state = sai_power_link_state,
+ .rx = saib_power_link_rx,
+ .state = saib_power_link_state,
};
@@ -630,7 +667,11 @@ sul_idle_cb(lws_sorted_usec_list_t *sul)
return;
/*
- * The plan is ask sai-power to turn us off...
+ * The plan is ask sai-power to turn us off... we don't know our
+ * dependency situation since we're just a standalone builder.
+ *
+ * We will have to let sai-power figure the deps out and say if
+ * it's willing to auto power-off or not.
*/
lwsl_notice("%s: creating sai-power ss...\n", __func__);
@@ -641,26 +682,6 @@ sul_idle_cb(lws_sorted_usec_list_t *sul)
return;
}
- /*
- * Give the http action some time to complete (else we will kill
- * everything including the http as soon as we progress on to shutdown)
- */
-
-#if defined(WIN32)
- Sleep(2000);
-#else
- sleep(2);
-#endif
-
- lwsl_notice("%s: doing shutdown...\n", __func__);
-
- /*
- * In the grace time for actioning the power-off, we should shutdown
- * cleanly
- */
-
- te = 0;
- n = write(lws_spawn_get_fd_stdxxx(lsp_suspender, 0), &te, 1);
#endif
}
diff --git a/src/power/p-comms.c b/src/power/p-comms.c
index b7794ff..4571f0b 100644
--- a/src/power/p-comms.c
+++ b/src/power/p-comms.c
@@ -47,6 +47,11 @@ saip_m_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
lwsl_info("%s: len %d, flags: %d (saip_server_t %p)\n", __func__, (int)len, flags, (void *)sps);
lwsl_hexdump_info(buf, len);
+ 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;
+ } lws_end_foreach_dll(px);
+
while (p < end) {
n = 0;
while (p < end && *p != ',')
@@ -58,41 +63,68 @@ saip_m_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
p++;
/*
- * Does this server list this platform?
+ * Does this server list this platform as having startable or ongoing
+ * tasks?
*/
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);
+ int hit = 0;
- if (!strcmp(sp->name, plat)) {
- /*
- * Server said this platform has pending jobs.
- * sai-power config says this builder can do
- * jobs on that platform. Let's make sure it
- * is powered on.
- */
- if (!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));
- }
+ /*
+ * How about any dependency listed?
+ */
+
+ 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(sp->power_on_type, "tasmota")) {
- if (lws_ss_create(lws_ss_cx_from_user(pss),
- 0, &ssi_saip_smartplug_t,
- (void *)sp->power_on_url, NULL, NULL, NULL)) {
- lwsl_err("%s: failed to create smartplug secure stream\n",
- __func__);
- }
+ if (!strcmp(sp1->name, plat)) {
+ sp->needed = 1;
+ break;
}
- }
+
+ } lws_end_foreach_dll(px1);
+
+ if (hit || !strcmp(sp->name, plat))
+ sp->needed = 1;
} lws_end_foreach_dll(px);
}
- (void)sps;
+ 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) {
+ lwsl_notice("%s: %s: needed\n", __func__, sp->name);
+
+ /*
+ * Server said this platform or at least one dependency
+ * has pending jobs. sai-power config says this builder
+ * can do jobs on that platform. Let's make sure it
+ * is powered on.
+ */
+ if (!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_notice("%s: starting tasmota\n", __func__);
+ if (lws_ss_create(lws_ss_cx_from_user(pss),
+ 0, &ssi_saip_smartplug_t,
+ (void *)sp->power_on_url, NULL, NULL, NULL)) {
+ lwsl_err("%s: failed to create smartplug secure stream\n",
+ __func__);
+ }
+ }
+ } else
+ lwsl_notice("%s: (%s not needed)\n", __func__, sp->name);
+
+ } lws_end_foreach_dll(px);
+
+ (void)sps;
return 0;
}
diff --git a/src/power/p-conf.c b/src/power/p-conf.c
index a907a80..2cd50a6 100644
--- a/src/power/p-conf.c
+++ b/src/power/p-conf.c
@@ -35,6 +35,7 @@ static const char * const paths_global[] = {
"servers[].url",
"servers[].platforms[].name",
"servers[].platforms[].host",
+ "servers[].platforms[].depends",
"servers[].platforms[].power-on.type",
"servers[].platforms[].power-on.mac",
"servers[].platforms[].power-on.url",
@@ -52,6 +53,7 @@ enum enum_paths_global {
LEJPM_SERVERS_URL,
LEJPM_SERVERS_PLATFORMS_NAME,
LEJPM_SERVERS_PLATFORMS_HOST,
+ LEJPM_SERVERS_PLATFORMS_DEPENDS,
LEJPM_SERVERS_PLATFORMS_POWER_ON_TYPE,
LEJPM_SERVERS_PLATFORMS_POWER_ON_MAC,
LEJPM_SERVERS_PLATFORMS_POWER_ON_URL,
@@ -149,6 +151,10 @@ saip_conf_global_cb(struct lejp_ctx *ctx, char reason)
pp = &a->sai_server_plat->host;
break;
+ case LEJPM_SERVERS_PLATFORMS_DEPENDS:
+ pp = &a->sai_server_plat->depends;
+ break;
+
case LEJPM_SERVERS_PLATFORMS_POWER_ON_TYPE:
pp = &a->sai_server_plat->power_on_type;
break;
@@ -221,6 +227,29 @@ saip_config_global(struct sai_power *power, const char *d)
n = (int)ctx.line;
lejp_destruct(&ctx);
+ /* let's wire up any dependencies so the dependent knows easily */
+
+ 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 (sp->depends) {
+ saip_server_plat_t *d = find_platform(power, sp->depends);
+
+ if (!d) {
+ lwsl_err("%s: can't find dependency '%s' on conf for '%s'\n", __func__,
+ sp->depends, sp->host);
+ return 1;
+ }
+
+ lws_dll2_add_tail(&d->dependencies_list, &sp->dependencies_owner);
+ }
+
+ } lws_end_foreach_dll(px1);
+ } lws_end_foreach_dll(px);
+
return 0;
}
diff --git a/src/power/p-private.h b/src/power/p-private.h
index 0a3bf94..fe08d82 100644
--- a/src/power/p-private.h
+++ b/src/power/p-private.h
@@ -58,11 +58,14 @@ struct saip_ws_pss;
typedef struct saip_server_plat {
struct lws_dll2 list;
+ lws_dll2_owner_t dependencies_owner;
+ lws_dll2_t dependencies_list;
lws_sorted_usec_list_t sul_delay_off;
const char *name;
const char *host;
+ const char *depends; /* depended-on plat must stay powered if we need power */
const char *power_on_type;
const char *power_on_url;
const char *power_on_mac;
@@ -70,6 +73,7 @@ typedef struct saip_server_plat {
const char *power_off_url;
char stay;
+ char needed;
} saip_server_plat_t;
@@ -109,6 +113,10 @@ struct sai_power {
const char *port; /* port we listen on */
};
+saip_server_plat_t *
+find_platform(struct sai_power *pwr, const char *host);
+
+
struct jpargs {
struct sai_power *power;
diff --git a/src/power/p-sai.c b/src/power/p-sai.c
index 999b982..b9bda4a 100644
--- a/src/power/p-sai.c
+++ b/src/power/p-sai.c
@@ -182,6 +182,7 @@ static const struct lws_protocols *pprotocols[] = {
&protocol_std,
NULL
};
+
static void
saip_sul_action_power_off(struct lws_sorted_usec_list *sul)
{
@@ -202,6 +203,25 @@ saip_sul_action_power_off(struct lws_sorted_usec_list *sul)
}
}
+saip_server_plat_t *
+find_platform(struct sai_power *pwr, const char *host)
+{
+ lws_start_foreach_dll(struct lws_dll2 *, px, pwr->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(host, sp->host))
+ return sp;
+
+ } lws_end_foreach_dll(px1);
+ } lws_end_foreach_dll(px);
+
+ return NULL;
+}
+
+
/*
* local-side h1 server for builders to connect to
*/
@@ -242,31 +262,14 @@ local_srv_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
return r;
}
-static saip_server_plat_t *
-find_platform(const char *host)
-{
- 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(host, sp->host))
- return sp;
-
- } lws_end_foreach_dll(px1);
- } lws_end_foreach_dll(px);
-
- return NULL;
-}
-
static lws_ss_state_return_t
local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
lws_ss_tx_ordinal_t ack)
{
local_srv_t *g = (local_srv_t *)userobj;
- saip_server_plat_t *sp;
char *path = NULL, pn[128];
+ saip_server_plat_t *sp;
+ int apo = 0;
size_t len;
// lwsl_ss_user(lws_ss_from_user(g), "state %s", lws_ss_state_name((int)state));
@@ -301,7 +304,7 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
if (len > 6 && !strncmp(path, "/stay/", 6)) {
lws_strnncpy(pn, &path[6], len - 6, sizeof(pn));
- sp = find_platform(pn);
+ sp = find_platform(&power, pn);
if (sp)
g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload),
@@ -314,7 +317,7 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
if (len > 10 && !strncmp(path, "/power-on/", 10)) {
lws_strnncpy(pn, &path[10], len - 10, sizeof(pn));
- sp = find_platform(pn);
+ sp = find_platform(&power, pn);
if (!sp) {
g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload),
"Unable to find host %s", pn);
@@ -355,6 +358,12 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
goto bail;
}
+ if (len > 16 && !strncmp(path, "/auto-power-off/", 16)) {
+ apo = 1;
+ lws_strnncpy(pn, &path[16], len - 16, sizeof(pn));
+ goto power_off;
+ }
+
if (len < 11 || strncmp(path, "/power-off/", 11)) {
g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload),
"URL path needs to start with /power-off/");
@@ -363,6 +372,8 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
lws_strnncpy(pn, &path[11], len - 11, sizeof(pn));
+power_off:
+
/*
* Let's have a look at the platform
*/
@@ -370,11 +381,36 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload),
"Unable to find host %s", pn);
- sp = find_platform(pn);
+ sp = find_platform(&power, pn);
if (sp) {
+
+ if (apo) {
+ char needs[128];
+
+ /*
+ * Since it's not a manual request,
+ * we should deny it if any deps still need us
+ */
+
+ needs[0] = '\0';
+ 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 (sp1->needed)
+ lws_snprintf(needs, sizeof(needs) - 1 - strlen(needs), "%s ", sp1->name);
+
+ } lws_end_foreach_dll(px1);
+
+ if (needs[0] || sp->needed) {
+ g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload),
+ "NAK: %s and/or dependencies still active: %s", pn, needs);
+ goto bail;
+ }
+ }
+
/*
- * OK this is it, schedule it to happen
- */
+ * OK this is it, schedule it to happen
+ */
lws_sul_schedule(lws_ss_cx_from_user(g), 0,
&sp->sul_delay_off,
saip_sul_action_power_off,
@@ -384,7 +420,7 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
__func__, sp->host);
g->size = (size_t)lws_snprintf(g->payload, sizeof(g->payload),
- "Scheduled powering off host %s", sp->host);
+ "ACK: Scheduled powering off host %s", sp->host);
sp->stay = 0; /* reset any manual power up */
}
diff --git a/src/power/p-smartplug.c b/src/power/p-smartplug.c
index 3a035dd..a0503f3 100644
--- a/src/power/p-smartplug.c
+++ b/src/power/p-smartplug.c
@@ -38,13 +38,13 @@ saip_spc_state(void *userobj, void *sh, lws_ss_constate_t state,
saip_smartplug_t *pss = (saip_smartplug_t *)userobj;
const char *op_url = (const char *)lws_ss_opaque_from_user(pss);
-// lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
-// (unsigned int)ack);
+ // lwsl_user("%s: %s, ord 0x%x\n", __func__, lws_ss_state_name((int)state),
+ // (unsigned int)ack);
switch (state) {
case LWSSSCS_CREATING:
-// lwsl_notice("%s: binding ss to %s\n", __func__, op_url);
+ lwsl_user("%s: binding ss to %s\n", __func__, op_url);
if (lws_ss_set_metadata(lws_ss_from_user(pss),
"url", op_url, strlen(op_url)))
@@ -52,6 +52,11 @@ saip_spc_state(void *userobj, void *sh, lws_ss_constate_t state,
return lws_ss_client_connect(lws_ss_from_user(pss));
+ case LWSSSCS_QOS_ACK_REMOTE:
+ case LWSSSCS_QOS_NACK_REMOTE:
+ case LWSSSCS_ALL_RETRIES_FAILED:
+ return LWSSSSRET_DESTROY_ME;
+
default:
break;
}
diff --git a/src/server/s-task.c b/src/server/s-task.c
index 74455d4..e0a6f58 100644
--- a/src/server/s-task.c
+++ b/src/server/s-task.c
@@ -584,7 +584,7 @@ sais_platforms_with_tasks_pending(struct vhd *vhd)
/*
* Iterate through the events looking at his event-specific database
- * for platforms that have pending tasks...
+ * for platforms that have pending or ongoing tasks...
*/
lws_start_foreach_dll(struct lws_dll2 *, p, o.head) {
@@ -597,7 +597,7 @@ sais_platforms_with_tasks_pending(struct vhd *vhd)
if (sqlite3_prepare_v2(pdb, "select distinct platform "
"from tasks where "
- "(state == 0 or state == 1)", -1, &sm,
+ "(state = 0 or state = 1 or state = 2)", -1, &sm,
NULL) != SQLITE_OK) {
lwsl_err("%s: Unable to %s\n",
__func__, sqlite3_errmsg(pdb));