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-08-06 16:30 UTC
Committer[]Andy Green <andy@warmcat.com> 2025-08-08 10:35 UTC
Tree1f4f44de115945e7a80ba1f2b28ce59697c6a483   Raw Patch
 
builder-db
builder-db
diff --git a/assets/sai.js b/assets/sai.js index 45259b5..49d5411 100644 --- a/assets/sai.js +++ b/assets/sai.js @@ -1717,6 +1717,22 @@ function post_login_form() /* stuff that has to be delayed until all the page assets are loaded */ window.addEventListener("load", function() { + const lnameInput = document.getElementById("lname"); + const lpassInput = document.getElementById("lpass"); + + function stopClickPropagation(event) { + // This is the key. It prevents the click event from + // reaching any parent elements. + event.stopPropagation(); + } + + if (lnameInput) { + lnameInput.addEventListener("click", stopClickPropagation); + } + + if (lpassInput) { + lpassInput.addEventListener("click", stopClickPropagation); + } if (document.getElementById("noscript")) document.getElementById("noscript").display = "none"; diff --git a/src/common/include/private.h b/src/common/include/private.h index e363331..ae50033 100644 --- a/src/common/include/private.h +++ b/src/common/include/private.h @@ -400,7 +400,10 @@ typedef struct sai_plat { struct lws *wsi; /* server side only */ lws_dll2_owner_t env_head; + uint64_t uid; lws_dll2_owner_t loads; + int online; /* 1 = connected, 0 = offline */ + uint64_t last_seen; /* unix time */ int instances; int ongoing; @@ -457,6 +460,7 @@ extern const lws_struct_map_t lsm_schema_json_map_event[1], lsm_resource[4] ; +extern const lws_struct_map_t lsm_plat[8]; extern const lws_ss_info_t ssi_said_logproxy; extern struct lws_ss_handle *ssh[3]; diff --git a/src/common/struct-metadata.c b/src/common/struct-metadata.c index ff74673..3fb39fc 100644 --- a/src/common/struct-metadata.c +++ b/src/common/struct-metadata.c @@ -40,11 +40,14 @@ const lws_struct_map_t lsm_load_report_members[] = { NULL, lsm_platform_load, "platforms"), }; -static const lws_struct_map_t lsm_plat[] = { +const lws_struct_map_t lsm_plat[] = { /* !!! keep extern length in common/include/private.h in sync */ + LSM_UNSIGNED (sai_event_t, uid, "uid"), LSM_STRING_PTR (sai_plat_t, name, "name"), LSM_UNSIGNED (sai_plat_t, ongoing, "ongoing"), LSM_UNSIGNED (sai_plat_t, instances, "instances"), LSM_STRING_PTR (sai_plat_t, platform, "platform"), + LSM_SIGNED (sai_plat_t, online, "online"), + LSM_UNSIGNED (sai_plat_t, last_seen, "last_seen"), LSM_CARRAY (sai_plat_t, peer_ip, "peer_ip"), }; @@ -62,6 +65,11 @@ const lws_struct_map_t lsm_schema_map_plat[] = { "com-warmcat-sai-ba"), }; +const lws_struct_map_t lsm_schema_sq3_map_plat[] = { + LSM_SCHEMA_DLL2 (sai_plat_t, sai_plat_list, NULL, lsm_plat, + "builders"), +}; + const lws_struct_map_t lsm_event[] = { LSM_UNSIGNED (sai_event_t, uid, "uid"), LSM_CARRAY (sai_event_t, repo_name, "repo_name"), diff --git a/src/server/s-comms.c b/src/server/s-comms.c index b4e2905..e069cad 100644 --- a/src/server/s-comms.c +++ b/src/server/s-comms.c @@ -499,6 +499,16 @@ callback_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, return -1; } + if (lws_struct_sq3_create_table(vhd->server.pdb, + lsm_schema_sq3_map_plat)) { + lwsl_err("%s: unable to create builders table\n", __func__); + return -1; + } + + sai_sqlite3_statement(vhd->server.pdb, + "CREATE UNIQUE INDEX IF NOT EXISTS name_idx ON builders (name)", + "create builder name index"); + lwsl_notice("%s: creating server stream\n", __func__); if (lws_ss_create(vhd->context, 0, &ssi_server, vhd, @@ -746,28 +756,28 @@ callback_ws(struct lws *wsi, enum lws_callback_reasons reason, void *user, lwsac_free(&pss->query_ac); lwsl_user("%s: CLOSED builder conn\n", __func__); - /* remove pss from vhd->builders */ + /* remove pss from vhd->builders (active connection list) */ lws_dll2_remove(&pss->same); /* - * Destroy any the builder-tracking objects that - * were using this departing connection + * Find any builder-tracking objects that were using this departing + * connection. Mark them as offline in the database. + * Also remove from the in-memory list of active builders. */ - lws_start_foreach_dll_safe(struct lws_dll2 *, p, p1, vhd->server.builder_owner.head) { sai_plat_t *cb = lws_container_of(p, sai_plat_t, sai_plat_list); + char q[256]; if (cb->wsi == wsi) { - /* remove builder object itself from server list */ - cb->wsi = NULL; + lwsl_warn("%s: Builder '%s' disconnected. Removing from live list.\n", + __func__, cb->name); + lws_snprintf(q, sizeof(q), "UPDATE builders SET online=0 WHERE name='%s'", cb->name); + sai_sqlite3_statement(vhd->server.pdb, q, "set builder offline"); + + /* remove from active in-memory list */ lws_dll2_remove(&cb->sai_plat_list); - /* - * free the deserialized builder object, - * everything he pointed to was overallocated - * when his deep copy was made - */ free(cb); } diff --git a/src/server/s-private.h b/src/server/s-private.h index 1ff2a36..1098f26 100644 --- a/src/server/s-private.h +++ b/src/server/s-private.h @@ -205,6 +205,9 @@ struct vhd { sais_t server; }; +extern const lws_struct_map_t lsm_plat[]; +extern const lws_struct_map_t lsm_schema_sq3_map_plat[]; + extern struct lws_context * sai_lws_context_from_json(const char *config_dir, struct lws_context_creation_info *info, diff --git a/src/server/s-websrv.c b/src/server/s-websrv.c index 325149a..2d351bb 100644 --- a/src/server/s-websrv.c +++ b/src/server/s-websrv.c @@ -153,7 +153,8 @@ sais_websrv_broadcast(struct lws_ss_handle *hsrv, const char *str, size_t len) int sais_list_builders(struct vhd *vhd) { - lws_dll2_t *walk = lws_dll2_get_head(&vhd->server.builder_owner); + lws_dll2_owner_t dbo; + struct lwsac *ac = NULL; char *p = vhd->json_builders, *end = p + sizeof(vhd->json_builders), subsequent = 0; lws_struct_serialize_t *js; @@ -161,13 +162,21 @@ sais_list_builders(struct vhd *vhd) size_t w; int n; - lwsl_err("%s: entry\n", __func__); + /* + * Query the database for ALL builders, online and offline, + * sorted by name. + */ + if (lws_struct_sq3_deserialize(vhd->server.pdb, NULL, "name ", + lsm_schema_sq3_map_plat, &dbo, &ac, 0, 100)) { + lwsl_err("%s: Failed to query builders from DB\n", __func__); + return 1; + } p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "{\"schema\":\"sai-builders\"," "\"platforms\":["); - while (end - p > 512 && walk) { + lws_start_foreach_dll(struct lws_dll2 *, walk, dbo.head) { b = lws_container_of(walk, sai_plat_t, sai_plat_list); @@ -176,8 +185,8 @@ sais_list_builders(struct vhd *vhd) LWS_ARRAY_SIZE(lsm_schema_map_plat_simple), 0, b); if (!js) { - lwsl_err("%s: failed at json serialize create\n", __func__); - return 1; + lwsl_err("%s: json serialize create failed\n", __func__); + goto bail; } if (subsequent) *p++ = ','; @@ -189,27 +198,27 @@ sais_list_builders(struct vhd *vhd) lws_struct_json_serialize_destroy(&js); if (n == LSJS_RESULT_ERROR) { - lwsl_err("%s: json serialize error\n", __func__); - return 1; + lwsl_err("%s: json serialize failed\n", __func__); + goto bail; } + } lws_end_foreach_dll(walk); - walk = walk->next; - if (!walk) { - - /* end of the list of builders */ - - p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "]}"); + /* end of the list of builders */ - lwsl_ss_notice(vhd->h_ss_websrv, "sai-server's WEB daemon server broadcasting to all WEB daemons: %s\n", vhd->json_builders); + p += lws_snprintf((char *)p, lws_ptr_diff_size_t(end, p), "]}"); - sais_websrv_broadcast(vhd->h_ss_websrv, - vhd->json_builders, - lws_ptr_diff_size_t(p, vhd->json_builders)); + /* + * This is the SERVER's WEB daemon server, broadcasting to all connected + * clients (the WEB daemons)... the list of BUILDERS + */ + sais_websrv_broadcast(vhd->h_ss_websrv, vhd->json_builders, + lws_ptr_diff_size_t(p, vhd->json_builders)); - return 0; - } - } + lwsac_free(&ac); + return 0; +bail: + lwsac_free(&ac); return 1; } diff --git a/src/server/s-ws-builder.c b/src/server/s-ws-builder.c index 7ff3ed0..9de422e 100644 --- a/src/server/s-ws-builder.c +++ b/src/server/s-ws-builder.c @@ -29,6 +29,21 @@ #include "s-private.h" +typedef struct { + int count; +} count_ctx_t; + +#if 0 +static int +online_builder_count_cb(void *priv, int cols, char **cv, char **cn) +{ + count_ctx_t *ctx = (count_ctx_t *)priv; + ctx->count++; + lwsl_err("%s: FOUND an online builder in DB: %s\n", __func__, cv[0]); + return 0; +} +#endif + enum sai_overview_state { SOS_EVENT, SOS_TASKS, @@ -329,107 +344,85 @@ handle: switch (pss->a.top_schema_index) { case SAIM_WSSCH_BUILDER_PLATS: - /* * builder is sending us an array of platforms it provides us */ pss->u.o = (sai_plat_owner_t *)pss->a.dest; - lwsl_notice("%s: SERVER: seen incoming platform list: count %d\n", __func__, - pss->u.o->plat_owner.count); - lws_start_foreach_dll(struct lws_dll2 *, pb, pss->u.o->plat_owner.head) { build = lws_container_of(pb, sai_plat_t, sai_plat_list); + sai_plat_t *live_cb; lwsl_notice("%s: seeing plat %s\n", __func__, build->name); /* - * ... so is this one a new guy? + * Step 1: Upsert this platform into the persistent database. */ - - cb = sais_builder_from_uuid(vhd, build->name); - if (!cb) { - char *cp; - - /* - * We need to make a persistent, deep, copy of - * the (from JSON) builder object representing - * this client. - * - * "platform" is eg "linux-ubuntu-bionic-arm64" - * and "name" is "hostname.<platform>". - */ - - if (!build->name || !build->platform) { - lwsl_err("%s: missing build '%s'/hostname '%s'\n", - __func__, - build->name ? build->name : "null", - build->platform ? build->platform : "null"); - return -1; - } - - cb = malloc(sizeof(*cb) + - strlen(build->name) + 1 + - strlen(build->platform) + 1); - - memset(cb, 0, sizeof(*cb)); - cp = (char *)&cb[1]; - - memcpy(cp, build->name, strlen(build->name) + 1); - cb->name = cp; - cp += strlen(build->name) + 1; - - memcpy(cp, build->platform, strlen(build->platform) + 1); - cb->platform = cp; - cp += strlen(build->platform) + 1; - - cb->ongoing = build->ongoing; - cb->instances = build->instances; - - cb->wsi = pss->wsi; - pss->announced = 0; - - /* Then attach the copy to the server in the vhd - */ - lws_dll2_add_tail(&cb->sai_plat_list, - &vhd->server.builder_owner); + build->online = 1; + build->last_seen = (uint64_t)lws_now_secs(); + lws_strncpy(build->peer_ip, pss->peer_ip, sizeof(build->peer_ip)); + if (lws_struct_sq3_upsert(vhd->server.pdb, "builders", lsm_plat, + LWS_ARRAY_SIZE(lsm_plat), build, "name")) { + lwsl_err("%s: Failed to upsert builder %s\n", + __func__, build->name); } /* - * It's a reconnect, update connection-specific things + * Step 2: Update the long-lived, malloc'd in-memory list. */ - - cb->wsi = pss->wsi; - - if (pss->peer_ip[0]) - lws_strncpy(cb->peer_ip, pss->peer_ip, sizeof(cb->peer_ip)); - - /* - * Even if he's not new, we should use his updated info about - * builder load - */ - - cb->ongoing = build->ongoing; - cb->instances = build->instances; - - lwsl_notice("%s: builder %s reports load %d/%d\n", - __func__, cb->name, cb->ongoing, - cb->instances); - + live_cb = sais_builder_from_uuid(vhd, build->name); + if (live_cb) { + /* Already exists (reconnect), just update dynamic info */ + live_cb->wsi = pss->wsi; + live_cb->ongoing = 0; /* Reset ongoing task count on connect */ + lws_strncpy(live_cb->peer_ip, pss->peer_ip, sizeof(live_cb->peer_ip)); + } else { + /* New builder, create a deep-copied, malloc'd object */ + size_t nlen = strlen(build->name) + 1; + size_t plen = strlen(build->platform) + 1; + live_cb = malloc(sizeof(*live_cb) + nlen + plen); + if (live_cb) { + char *p_str = (char *)(live_cb + 1); + memset(live_cb, 0, sizeof(*live_cb)); + live_cb->name = p_str; + memcpy(p_str, build->name, nlen); + live_cb->platform = p_str + nlen; + memcpy(p_str + nlen, build->platform, plen); + live_cb->instances = build->instances; + live_cb->wsi = pss->wsi; + lws_strncpy(live_cb->peer_ip, pss->peer_ip, sizeof(live_cb->peer_ip)); + lws_dll2_add_tail(&live_cb->sai_plat_list, &vhd->server.builder_owner); + } + } } lws_end_foreach_dll(pb); + /* The lwsac from the parsed message is now completely disposable */ lwsac_free(&pss->a.ac); - /* - * look if we should offer the builder a task, given the - * platforms he's offering - */ - - if (sais_allocate_task(vhd, pss, cb, cb->platform) < 0) - goto bail; + * Now, iterate through the in-memory list of online builders and + * try to allocate a task for each platform that belongs to the + * builder that just connected. + */ + lws_start_foreach_dll(struct lws_dll2 *, p, vhd->server.builder_owner.head) { + cb = lws_container_of(p, sai_plat_t, sai_plat_list); + if (cb->wsi == pss->wsi) { + /* This platform belongs to the connection that sent the message */ + if (sais_allocate_task(vhd, pss, cb, cb->platform) < 0) + goto bail; + } + } lws_end_foreach_dll(p); + + lws_start_foreach_dll(struct lws_dll2 *, p, vhd->server.builder_owner.head) { + cb = lws_container_of(p, sai_plat_t, sai_plat_list); + if (cb->wsi == pss->wsi) { + /* This platform belongs to the connection that sent the message */ + if (sais_allocate_task(vhd, pss, cb, cb->platform) < 0) + goto bail; + } + } lws_end_foreach_dll(p); /* * If we did allocate a task in pss->a.ac, responsibility of @@ -495,6 +488,7 @@ bail: rej = (sai_rejection_t *)pss->a.dest; + rej->host_platform[sizeof(rej->host_platform) - 1] = '\0'; cb = sais_builder_from_uuid(vhd, rej->host_platform); if (!cb) { lwsl_info("%s: unknown builder %s rejecting\n",
Page fetched 0s ago, creation time: 6ms (vhost etag hits: 0%, cache hits: 0%)