| /*
* sai-virt - src/virt/v-ws-server.c
*
* Copyright (C) 2019 - 2026 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.
*/
#include <libwebsockets.h>
#include <string.h>
#include "v-private.h"
/*
* When we connect, we masquerade as a builder/pcon and send our platforms
*/
static lws_ss_state_return_t
saiv_server_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf,
size_t *len, int *flags)
{
saiv_server_link_t *g = (saiv_server_link_t *)userobj;
return sai_ss_tx_from_buflist_helper(g->ss, &g->bl_tx, buf, len, flags);
}
static lws_ss_state_return_t
saiv_server_rx(void *userobj, const uint8_t *buf, size_t len, int flags)
{
struct lejp_ctx ctx;
lws_struct_args_t a;
int m;
/*
* We receive JSON from sai-server, usually com.warmcat.sai.power.pending_tasks
*/
memset(&a, 0, sizeof(a));
a.map_st[0] = lsm_schema_pending_tasks;
a.map_entries_st[0] = LWS_ARRAY_SIZE(lsm_schema_pending_tasks);
a.ac_block_size = 512;
lws_struct_json_init_parse(&ctx, NULL, &a);
m = lejp_parse(&ctx, (uint8_t *)buf, (int)len);
if (m < 0) {
lwsl_err("%s: JSON decode failed '%s'\n", __func__, lejp_error_to_string(m));
return LWSSSSRET_OK;
}
if (!a.dest) {
lwsac_free(&a.ac);
return LWSSSSRET_OK;
}
if (a.top_schema_index == 0) {
sai_platform_pending_tasks_t *pt = (sai_platform_pending_tasks_t *)a.dest;
lwsl_notice("%s: Pending tasks for pcons: %s\n", __func__, pt->pcons);
lws_start_foreach_dll(struct lws_dll2 *, p, pt->tasks.head) {
sai_platform_pending_task_t *t = lws_container_of(p, sai_platform_pending_task_t, list);
lwsl_notice(" - %s: %u pending\n", t->plat, t->pending);
if (t->pending > 0 && virt.ops) {
virt.ops->spawn(&virt, t->plat);
}
} lws_end_foreach_dll(p);
}
lwsac_free(&a.ac);
return LWSSSSRET_OK;
}
static lws_ss_state_return_t
saiv_server_state(void *userobj, void *sh, lws_ss_constate_t state,
lws_ss_tx_ordinal_t ack)
{
saiv_server_link_t *g = (saiv_server_link_t *)userobj;
sai_builder_registration_t r;
struct lwsac *ac = NULL;
switch (state) {
case LWSSSCS_CREATING:
lwsl_notice("%s: CREATING\n", __func__);
/* We'd set metadata url here from the config, skipped for skeleton */
break;
case LWSSSCS_CONNECTED:
lwsl_notice("%s: Connected to sai-server\n", __func__);
memset(&r, 0, sizeof(r));
lws_strncpy(r.builder_name, virt.hostname, sizeof(r.builder_name));
lws_strncpy(r.power_controller_name, virt.hostname, sizeof(r.power_controller_name));
/* We can spawn mac-m1, windows-10, etc. (Mocked for now) */
const char *plats[] = {"windows-x86_64", "mac-m1"};
for (size_t i = 0; i < LWS_ARRAY_SIZE(plats); i++) {
sai_builder_platform_t *bp = lwsac_use_zero(&ac, sizeof(*bp), 512);
if (bp) {
lws_strncpy(bp->name, plats[i], sizeof(bp->name));
lws_dll2_add_tail(&bp->list, &r.platforms_owner);
}
}
sai_ss_serialize_queue_helper(g->ss, &g->bl_tx,
lsm_schema_builder_registration,
LWS_ARRAY_SIZE(lsm_schema_builder_registration),
&r);
lwsac_free(&ac);
break;
case LWSSSCS_DISCONNECTED:
lwsl_notice("%s: Disconnected\n", __func__);
lws_buflist_destroy_all_segments(&g->bl_tx);
break;
default:
break;
}
return LWSSSSRET_OK;
}
const lws_ss_info_t ssi_saiv_server_link_t = {
.handle_offset = offsetof(saiv_server_link_t, ss),
.opaque_user_data_offset = offsetof(saiv_server_link_t, opaque_data),
.rx = saiv_server_rx,
.tx = saiv_server_tx,
.state = saiv_server_state,
.user_alloc = sizeof(saiv_server_link_t),
.streamtype = "sai_power_client"
};
|