diff --git a/src/power/p-http-api.c b/src/power/p-http-api.c
index ce294df..fc58279 100644
--- a/src/power/p-http-api.c
+++ b/src/power/p-http-api.c
@@ -183,6 +183,9 @@ LWS_SS_USER_TYPEDEF
char payload[200];
size_t size;
size_t pos;
+ struct lws_struct_args a;
+ struct lejp_ctx ctx;
+ saip_builder_t *b;
} local_srv_t;
static lws_ss_state_return_t
@@ -216,6 +219,100 @@ local_srv_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
}
static lws_ss_state_return_t
+local_srv_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
+{
+ local_srv_t *g = (local_srv_t *)userobj;
+ struct lws_ss_handle *h = lws_ss_from_user(g);
+ saip_pcon_t *pc;
+ saip_builder_t *b;
+
+ if (!g->ctx.user) { /* first time */
+ memset(&g->a, 0, sizeof(g->a));
+ g->a.map_st[0] = lsm_schema_builder_registration;
+ g->a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema_builder_registration);
+ g->a.ac_block_size = 2048;
+ lws_struct_json_init_parse(&g->ctx, NULL, &g->a);
+ }
+
+ if (lejp_parse(&g->ctx, buf, (int)len) < 0 || !g->a.dest) {
+ lwsl_ss_warn(h, "JSON decode failed");
+ lwsac_free(&g->a.ac);
+ return LWSSSSRET_DISCONNECT_ME;
+ }
+
+ if (g->a.top_schema_index == 0) {
+ sai_builder_registration_t *r = (sai_builder_registration_t *)g->a.dest;
+
+ lwsl_ss_notice(h, "Registered builder '%s' on pcon '%s'",
+ r->builder_name, r->power_controller_name);
+
+ /* Find the PCON */
+ pc = saip_pcon_by_name(&power, r->power_controller_name);
+ if (!pc) {
+ lwsl_ss_warn(h, "Unknown PCON '%s', creating it", r->power_controller_name);
+ /* Dynamically create PCON if missing */
+ pc = saip_pcon_create(&power, r->power_controller_name);
+ }
+
+ if (pc) {
+ /* Check if builder already exists */
+ int found = 0;
+ lws_start_foreach_dll(struct lws_dll2 *, b_node, pc->registered_builders_owner.head) {
+ saip_builder_t *sb = lws_container_of(b_node, saip_builder_t, list);
+ if (!strcmp(sb->name, r->builder_name)) {
+ lwsl_ss_notice(h, "Builder '%s' re-connected to PCON '%s'", r->builder_name, pc->name);
+ /* sb->wsi = ...; */ /* We don't have wsi here easily, but we have SS handle? Not needed for logic. */
+ g->b = sb; /* Link user object to builder */
+ found = 1;
+ break;
+ }
+ } lws_end_foreach_dll(b_node);
+
+ if (!found) {
+ lwsl_ss_notice(h, "Adding builder '%s' to PCON '%s'", r->builder_name, pc->name);
+ b = malloc(sizeof(*b));
+ if (b) {
+ memset(b, 0, sizeof(*b));
+ lws_strncpy(b->name, r->builder_name, sizeof(b->name));
+ /* b->wsi = ...; */
+ g->b = b;
+ lws_dll2_add_tail(&b->list, &pc->registered_builders_owner);
+ } else {
+ lwsl_ss_err(h, "OOM allocating builder");
+ }
+ }
+
+ /* Store platforms */
+ if (g->b) {
+ /* Clear existing platforms first? Or just append? */
+ lws_dll2_owner_clear(&g->b->platforms_owner); /* Assuming we have a way to free items, but lwsac managed? No, these are manual. */
+ /* Actually we used lwsac for deserialization, but we need to PERSIST this data. */
+ /* We need to copy from 'r->platforms_owner' to 'g->b->platforms_owner' */
+
+ lws_start_foreach_dll(struct lws_dll2 *, p, r->platforms_owner.head) {
+ sai_builder_platform_t *bp = lws_container_of(p, sai_builder_platform_t, list);
+ saip_builder_platform_t *sbp = malloc(sizeof(*sbp));
+ if (sbp) {
+ memset(sbp, 0, sizeof(*sbp));
+ lws_strncpy(sbp->name, bp->name, sizeof(sbp->name));
+ lws_dll2_add_tail(&sbp->list, &g->b->platforms_owner);
+ }
+ } lws_end_foreach_dll(p);
+ }
+
+ /* Trigger a check since we have a new builder (it's alive!) */
+ saip_pcon_start_check();
+
+ /* Send update to sai-server */
+ saip_queue_stay_info(lws_container_of(power.sai_server_owner.head, saip_server_t, list));
+ }
+ }
+
+ lwsac_free(&g->a.ac);
+ return LWSSSSRET_OK;
+}
+
+static lws_ss_state_return_t
local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
lws_ss_tx_ordinal_t ack)
{
@@ -232,6 +329,16 @@ local_srv_state(void *userobj, void *sh, lws_ss_constate_t state,
case LWSSSCS_CREATING:
return lws_ss_request_tx(lws_ss_from_user(g));
+ case LWSSSCS_DISCONNECTED:
+ if (g->b) {
+ /* Mark as offline but don't delete */
+ /* g->b->wsi = NULL; */
+ g->b = NULL;
+ }
+ /* Clean up lejp if pending? */
+ lws_struct_json_init_parse(&g->ctx, NULL, NULL); /* Reset */
+ break;
+
case LWSSSCS_SERVER_TXN:
lws_ss_get_metadata(lws_ss_from_user(g), "path", (const void **)&path, &len);
@@ -410,7 +517,7 @@ power_off:
/*
* OK this is it, schedule it to happen
*/
- lws_sul_schedule(lws_ss_cx_from_user(g), 0,
+ lws_sul_schedule(lws_ss_from_user(g), 0,
&pc->sul_delay_off,
saip_sul_action_power_off,
SAI_POWERDOWN_HOLDOFF_US);
@@ -438,5 +545,6 @@ bail:
LWS_SS_INFO("local", local_srv_t)
.tx = local_srv_tx,
+ .rx = local_srv_rx,
.state = local_srv_state,
};
diff --git a/src/power/p-private.h b/src/power/p-private.h
index fc94cc5..63013bc 100644
--- a/src/power/p-private.h
+++ b/src/power/p-private.h
@@ -93,6 +93,7 @@ typedef struct saip_pcon {
/* Represents a builder connected to us */
typedef struct saip_builder {
struct lws_dll2 list; /* in saip_pcon.registered_builders_owner */
+ lws_dll2_owner_t platforms_owner; /* saip_builder_platform_t */
char name[64];
@@ -100,6 +101,11 @@ typedef struct saip_builder {
struct lws *wsi;
} saip_builder_t;
+typedef struct saip_builder_platform {
+ lws_dll2_t list;
+ char name[64];
+} saip_builder_platform_t;
+
struct saip_ws_pss;
diff --git a/src/power/p-sai.c b/src/power/p-sai.c
index 451a2ac..2ee1855 100644
--- a/src/power/p-sai.c
+++ b/src/power/p-sai.c
@@ -180,120 +180,8 @@ callback_std(struct lws *wsi, enum lws_callback_reasons reason, void *user,
static const struct lws_protocols protocol_std =
{ "protocol_std", callback_std, 0, 0 };
-/*
- * Builder connection handling
- */
-
-int
-callback_builder(struct lws *wsi, enum lws_callback_reasons reason,
- void *user, void *in, size_t len)
-{
- struct lejp_ctx ctx;
- lws_struct_args_t a;
- saip_builder_t *b, **pb = (saip_builder_t **)user;
- saip_pcon_t *pc;
-
- switch (reason) {
- case LWS_CALLBACK_ESTABLISHED:
- lwsl_user("%s: builder connected\n", __func__);
- *pb = NULL; /* Ensure user data is clean */
- break;
-
- case LWS_CALLBACK_RECEIVE:
- // lwsl_hexdump_notice(in, len);
- memset(&a, 0, sizeof(a));
- a.map_st[0] = lsm_schema_builder_registration;
- a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema_builder_registration);
- a.ac_block_size = 2048;
-
- lws_struct_json_init_parse(&ctx, NULL, &a);
- if (lejp_parse(&ctx, (uint8_t *)in, (int)len) < 0 || !a.dest) {
- lwsl_warn("%s: JSON decode failed\n", __func__);
- lwsac_free(&a.ac);
- return -1;
- }
-
- if (a.top_schema_index == 0) {
- sai_builder_registration_t *r = (sai_builder_registration_t *)a.dest;
-
- lwsl_notice("%s: Registered builder '%s' on pcon '%s'\n",
- __func__, r->builder_name, r->power_controller_name);
-
- /* Find the PCON */
- pc = saip_pcon_by_name(&power, r->power_controller_name);
- if (pc) {
- /* Check if builder already exists */
- int found = 0;
- lws_start_foreach_dll(struct lws_dll2 *, b_node, pc->registered_builders_owner.head) {
- saip_builder_t *sb = lws_container_of(b_node, saip_builder_t, list);
- if (!strcmp(sb->name, r->builder_name)) {
- lwsl_notice("%s: Builder '%s' re-connected to PCON '%s'\n", __func__, r->builder_name, pc->name);
- sb->wsi = wsi;
- *pb = sb;
- found = 1;
- break;
- }
- } lws_end_foreach_dll(b_node);
-
- if (!found) {
- lwsl_notice("%s: Adding builder '%s' to PCON '%s'\n", __func__, r->builder_name, pc->name);
- /* Create/Update builder entry using malloc */
- b = malloc(sizeof(*b));
- if (b) {
- memset(b, 0, sizeof(*b));
- lws_strncpy(b->name, r->builder_name, sizeof(b->name));
- b->wsi = wsi;
-
- /* Store pointer in user data for cleanup */
- *pb = b;
-
- /* Add to list */
- lws_dll2_add_tail(&b->list, &pc->registered_builders_owner);
- } else
- lwsl_err("%s: OOM allocating builder\n", __func__);
- }
-
- /* Trigger a check since we have a new builder (it's alive!) */
- saip_pcon_start_check();
-
- /* Send update to sai-server? */
- saip_queue_stay_info(lws_container_of(power.sai_server_owner.head, saip_server_t, list));
-
- } else {
- lwsl_err("%s: Unknown PCON '%s' for builder '%s'\n",
- __func__, r->power_controller_name, r->builder_name);
- }
-
- }
- lwsac_free(&a.ac);
- break;
-
- case LWS_CALLBACK_CLOSED:
- lwsl_user("%s: builder disconnected\n", __func__);
- b = *pb;
- if (b) {
- /* Just mark it as offline, don't remove or free */
- b->wsi = NULL;
- /* Don't free *pb, we want to keep the struct */
- /* *pb = NULL; */
-
- /* Update state */
- saip_pcon_start_check();
- }
- break;
-
- default:
- break;
- }
- return 0;
-}
-
-static const struct lws_protocols protocol_builder =
- { "com-warmcat-sai-builder", callback_builder, sizeof(saip_builder_t *), 0 };
-
static const struct lws_protocols *pprotocols[] = {
&protocol_std,
- &protocol_builder,
NULL
};