diff --git a/assets/sai.css b/assets/sai.css
index b45379d..03cccc9 100644
--- a/assets/sai.css
+++ b/assets/sai.css
@@ -65,6 +65,10 @@ img.zup {
padding: 20px;
border: 1px solid #ccc;
}
+
+.fading-out {
+ opacity: 0;
+}
[type=radio]:checked ~ label {
background: white;
border-bottom: 1px solid white;
@@ -981,6 +985,9 @@ body.overlay-active {
font-size: 7pt;
text-align: left;
}
+.spreadsheet tr {
+ transition: opacity 3s linear;
+}
.spreadsheet th {
background-color: #f2f2f2;
}
diff --git a/assets/sai.js b/assets/sai.js
index 94f7473..14f6457 100644
--- a/assets/sai.js
+++ b/assets/sai.js
@@ -396,7 +396,8 @@ var lang_zhs = "{" +
var logs = "", redpend = 0, gitohashi_integ = 0, authd = 0, exptimer, auth_user = "",
logAnsiState = {},
- ongoing_task_activities = {}, last_log_timestamp = 0, spreadsheet_data_cache = {}, loadreport_data_cache = {};
+ ongoing_task_activities = {}, last_log_timestamp = 0, spreadsheet_data_cache = {}, loadreport_data_cache = {},
+ fadingTasks = new Map();
function update_task_activities() {
for (const uuid in ongoing_task_activities) {
@@ -508,40 +509,107 @@ function hsanitize(s)
}).replace(/\r\n/g, '\n').replace(/\n/g, '<br>');
}
-function renderSpreadsheet(tasks) {
- if (!tasks || tasks.length === 0) {
- return '';
- }
+function createTaskRow(task, now_ut) {
+ const tr = document.createElement("tr");
+ tr.id = "task-row-" + task.task_uuid;
+
+ let s1 = "";
+ let qc;
+ for (qc = 0; qc <= task.build_step; qc++)
+ s1 += "▣";
+ while (qc <= task.total_steps) {
+ s1 += "□";
+ qc++;
+ }
- tasks.sort((a, b) => b.started - a.started || a.task_name.localeCompare(b.task_name));
+ tr.innerHTML = `<td>${s1}</td>` +
+ `<td>${agify(now_ut, task.started)} ago</td>` +
+ `<td><a href="index.html?task=${hsanitize(task.task_uuid)}">${hsanitize(task.task_name)}</a></td>`;
+ return tr;
+}
- var now_ut = Math.round((new Date().getTime() / 1000));
- let html = '<table class="spreadsheet">' +
- '<thead><tr>' +
- '<th>Build Step</th>' +
- '<th>Since</th>' +
- '<th>Task</th>' +
- '</tr></thead><tbody>';
-
- for (const task of tasks) {
- var s1 = "", qc;
-
- for (qc = 0; qc <= task.build_step; qc++)
- s1 += "▣";
-
- while (qc <= task.total_steps) {
- s1 += "□";
- qc++;
- }
- html += '<tr>' +
- `<td>` + s1 + `</td>` +
- `<td>${agify(now_ut, task.started)} ago</td>` +
- `<td><a href="index.html?task=${hsanitize(task.task_uuid)}">${hsanitize(task.task_name)}</a></td>` +
- '</tr>';
+function updateTaskRow(tr, task, now_ut) {
+ let s1 = "";
+ let qc;
+ for (qc = 0; qc <= task.build_step; qc++)
+ s1 += "▣";
+ while (qc <= task.total_steps) {
+ s1 += "□";
+ qc++;
+ }
+ tr.innerHTML = `<td>${s1}</td>` +
+ `<td>${agify(now_ut, task.started)} ago</td>` +
+ `<td><a href="index.html?task=${hsanitize(task.task_uuid)}">${hsanitize(task.task_name)}</a></td>`;
+}
+
+function updateSpreadsheetDOM(container, tasks) {
+ if (!tasks || !tasks.length) {
+ container.innerHTML = "";
+ return;
}
- html += '</tbody></table>';
- return html;
+ tasks.sort((a, b) => b.started - a.started || a.task_name.localeCompare(b.task_name));
+
+ let table = container.querySelector("table.spreadsheet");
+ if (!table) {
+ container.innerHTML = '<table class="spreadsheet">' +
+ '<thead><tr><th>Build Step</th><th>Since</th><th>Task</th></tr></thead>' +
+ '<tbody></tbody></table>';
+ table = container.querySelector("table.spreadsheet");
+ }
+ const tbody = table.querySelector("tbody");
+ const now_ut = Math.round((new Date().getTime() / 1000));
+
+ const existingRows = new Map();
+ for (const row of tbody.children) {
+ existingRows.set(row.id, row);
+ }
+
+ const newOrUpdatedTaskIds = new Set();
+ for (const task of tasks) {
+ const taskRowId = "task-row-" + task.task_uuid;
+ newOrUpdatedTaskIds.add(taskRowId);
+ const row = existingRows.get(taskRowId);
+
+ if (row) {
+ if (fadingTasks.has(task.task_uuid)) {
+ clearTimeout(fadingTasks.get(task.task_uuid));
+ fadingTasks.delete(task.task_uuid);
+ row.classList.remove("fading-out");
+ }
+ updateTaskRow(row, task, now_ut);
+ } else {
+ tbody.appendChild(createTaskRow(task, now_ut));
+ }
+ }
+
+ for (const [rowId, row] of existingRows) {
+ if (!newOrUpdatedTaskIds.has(rowId)) {
+ const task_uuid = rowId.substring(9);
+ if (!fadingTasks.has(task_uuid)) {
+ row.classList.add("fading-out");
+ const timer = setTimeout(() => {
+ tbody.removeChild(row);
+ fadingTasks.delete(task_uuid);
+ }, 3000);
+ fadingTasks.set(task_uuid, timer);
+ }
+ }
+ }
+
+ const rows = Array.from(tbody.children);
+ const taskMap = new Map(tasks.map(t => ["task-row-" + t.task_uuid, t]));
+
+ rows.sort((rowA, rowB) => {
+ const taskA = taskMap.get(rowA.id);
+ const taskB = taskMap.get(rowB.id);
+ if (!taskA || !taskB) return 0;
+ return (taskB.started - taskA.started) || taskA.task_name.localeCompare(taskB.task_name);
+ });
+
+ for (const row of rows) {
+ tbody.appendChild(row);
+ }
}
var pos = 0, lli = 1, lines = "", times = "", locked = 1, tfirst = 0,
@@ -595,38 +663,43 @@ function agify(now, secs)
function aging()
{
- var n, next = 24 * 3600,
- now_ut = Math.round((new Date().getTime() / 1000));
-
- for (n = 0; n < age_names.length; n++) {
- var m, elems = document.getElementsByClassName(
- "age-" + n), ne = elems.length,
- a = new Array(), ee = new Array();
+ var n, next = 24 * 3600,
+ now_ut = Math.round((new Date().getTime() / 1000));
- if (elems.length && age_upd[n] < next)
- next = age_upd[n];
-
- for (m = 0; m < ne; m++) {
- var e = elems[m], secs = elems[m].getAttribute("ut");
+ var selector = [];
+ for (n = 0; n < age_names.length; n++)
+ selector.push(".age-" + n);
+
+ var elems = document.querySelectorAll(selector.join(", "));
+ var list = [];
+ for (n = 0; n < elems.length; n++)
+ list.push(elems[n]);
+
+ for (n = 0; n < list.length; n++) {
+ var e = list[n];
+ var secs = e.getAttribute("ut");
+ var d = Math.abs(now_ut - secs);
+
+ for (var j = 0; j < age_limit.length; j++) {
+ if (d < age_limit[j] || age_limit[j] === 0) {
+ if (age_upd[j] < next)
+ next = age_upd[j];
+ break;
+ }
+ }
- a.push(agify(now_ut, secs));
- ee.push(e);
- }
-
- for (m = 0; m < ee.length; m++) {
- ee[m].innerHTML = a[m];
- }
- }
+ e.outerHTML = agify(now_ut, secs);
+ }
if (next < 5)
next = 5;
- /*
- * We only need to come back when the age might have changed.
- * Eg, if everything is counted in hours already, once per
- * 5 minutes is accurate enough.
- */
- window.setTimeout(aging, next * 1000);
+ /*
+ * We only need to come back when the age might have changed.
+ * Eg, if everything is counted in hours already, once per
+ * 5 minutes is accurate enough.
+ */
+ window.setTimeout(aging, next * 1000);
}
var sai, jso, s, sai_arts = "";
@@ -1152,6 +1225,56 @@ function createBuilderDiv(plat) {
return platDiv;
}
+function updateSpreadsheetCell(cell, platName) {
+ let best_match_key = null;
+ for (const short_name in spreadsheet_data_cache) {
+ if (platName.startsWith(short_name)) {
+ if (!best_match_key || short_name.length > best_match_key.length) {
+ best_match_key = short_name;
+ }
+ }
+ }
+
+ if (best_match_key) {
+ cell.innerHTML = renderSpreadsheet(spreadsheet_data_cache[best_match_key]);
+ aging();
+ } else {
+ cell.innerHTML = ""; // Clear it if no data
+ }
+}
+
+function createBuilderRow(plat) {
+ const tr = document.createElement("tr");
+ tr.id = "row-" + plat.name;
+
+ const tdInfo = document.createElement("td");
+ tdInfo.className = "builder-info";
+ const builderDiv = createBuilderDiv(plat);
+ tdInfo.appendChild(builderDiv);
+ tr.appendChild(tdInfo);
+
+ const tdSpreadsheet = document.createElement("td");
+ tdSpreadsheet.className = "spreadsheet-container";
+ tdSpreadsheet.id = "spreadsheet-" + plat.name;
+ updateSpreadsheetCell(tdSpreadsheet, plat.name);
+ tr.appendChild(tdSpreadsheet);
+
+ return tr;
+}
+
+function updateBuilderRow(row, plat) {
+ const tdInfo = row.querySelector(".builder-info");
+ const tdSpreadsheet = row.querySelector(".spreadsheet-container");
+
+ // Update builder info div
+ // This is simple enough that a full replacement is fine and ensures listeners are correct.
+ tdInfo.innerHTML = "";
+ tdInfo.appendChild(createBuilderDiv(plat));
+
+ // Update spreadsheet view for this builder
+ updateSpreadsheetCell(tdSpreadsheet, plat.name);
+}
+
function ws_open_sai()
{
var s = "", q, qa, qi, q5, q5s;
@@ -1319,66 +1442,62 @@ function ws_open_sai()
const buildersContainer = document.getElementById("sai_builders");
if (!buildersContainer) { break; }
- let platformsArray = null;
- if (jso.platforms && Array.isArray(jso.platforms)) {
- platformsArray = jso.platforms;
- } else if (jso.builders && Array.isArray(jso.builders)) {
- platformsArray = jso.builders;
- }
+ let platformsArray = (jso.platforms && Array.isArray(jso.platforms)) ? jso.platforms :
+ (jso.builders && Array.isArray(jso.builders)) ? jso.builders : null;
+
if (!platformsArray) {
buildersContainer.innerHTML = ""; // Clear display if data is invalid
break;
}
+ platformsArray.sort((a, b) => (a.name && b.name) ? a.name.localeCompare(b.name) : 0);
+
+ let table = buildersContainer.querySelector("table.builders");
+ if (!table) {
+ buildersContainer.innerHTML = ""; // Clear placeholder
+ table = document.createElement("table");
+ table.className = "builders";
+ table.appendChild(document.createElement("tbody"));
+ buildersContainer.appendChild(table);
+ }
+ const tbody = table.querySelector("tbody");
// --- Reconciliation Logic ---
+ let platIdx = 0;
+ let currentRow = tbody.firstChild;
- buildersContainer.innerHTML = " "; // Clear for safety
- const table = document.createElement("table");
- table.className = "builders";
- const tbody = document.createElement("tbody");
- table.appendChild(tbody);
+ while (platIdx < platformsArray.length) {
+ const plat = platformsArray[platIdx];
- platformsArray.sort((a, b) => {
- if (a.name && b.name) {
- return a.name.localeCompare(b.name);
- }
- return 0; // Don't sort if names are missing
- });
-
- for (const plat of platformsArray) {
- const tr = document.createElement("tr");
-
- const tdInfo = document.createElement("td");
- tdInfo.className = "builder-info";
- const builderDiv = createBuilderDiv(plat);
- tdInfo.appendChild(builderDiv);
- tr.appendChild(tdInfo);
-
- const tdSpreadsheet = document.createElement("td");
- tdSpreadsheet.className = "spreadsheet-container";
- tdSpreadsheet.id = "spreadsheet-" + plat.name;
-
- let best_match_key = null;
- for (const short_name in spreadsheet_data_cache) {
- if (plat.name.startsWith(short_name)) {
- if (!best_match_key || short_name.length > best_match_key.length) {
- best_match_key = short_name;
- }
- }
+ if (!currentRow) {
+ tbody.appendChild(createBuilderRow(plat));
+ platIdx++;
+ continue;
}
- if (best_match_key) {
- tdSpreadsheet.innerHTML = renderSpreadsheet(spreadsheet_data_cache[best_match_key]);
- aging();
+ const rowPlatName = currentRow.id.substring(4); // "row-..."
+ const comparison = plat.name.localeCompare(rowPlatName);
+
+ if (comparison === 0) {
+ updateBuilderRow(currentRow, plat);
+ platIdx++;
+ currentRow = currentRow.nextSibling;
+ } else if (comparison < 0) {
+ tbody.insertBefore(createBuilderRow(plat), currentRow);
+ platIdx++;
+ } else { // comparison > 0
+ const nextRow = currentRow.nextSibling;
+ tbody.removeChild(currentRow);
+ currentRow = nextRow;
}
-
- tr.appendChild(tdSpreadsheet);
-
- tbody.appendChild(tr);
}
- buildersContainer.appendChild(table);
+ // Remove any remaining old rows at the end
+ while (currentRow) {
+ const nextRow = currentRow.nextSibling;
+ tbody.removeChild(currentRow);
+ currentRow = nextRow;
+ }
break;
case "com.warmcat.sai.build-metric":
@@ -1752,9 +1871,10 @@ function ws_open_sai()
const spreadsheetContainer = document.getElementById('spreadsheet-' + jso.builder_name);
if (spreadsheetContainer) {
- spreadsheetContainer.innerHTML = renderSpreadsheet(spreadsheet_data_cache[jso.builder_name]);
- if (spreadsheet_data_cache[jso.builder_name])
+ updateSpreadsheetDOM(spreadsheetContainer, spreadsheet_data_cache[jso.builder_name]);
+ if (spreadsheet_data_cache[jso.builder_name]) {
aging();
+ }
}
break;
diff --git a/build.sh b/build.sh
deleted file mode 100644
index b61cda0..0000000
--- a/build.sh
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-set -e
-git clone https://github.com/warmcat/libwebsockets.git
-cd libwebsockets
-mkdir build
-cd build
-cmake .. -DLWS_WITH_JOSE=1
-sudo make install
-cd ../..
-mkdir build
-cd build
-cmake ..
-make -j8
diff --git a/src/common/include/private.h b/src/common/include/private.h
index 274c7a1..344c5cc 100644
--- a/src/common/include/private.h
+++ b/src/common/include/private.h
@@ -56,43 +56,43 @@ typedef enum {
} sai_event_state_t;
enum {
- SAISPRF_TIMEDOUT = 0x1000,
- SAISPRF_TERMINATED = 0x2000,
- SAISPRF_EXIT = 0x8000,
- SAISPRF_SIGNALLED = 0x4000,
+ SAISPRF_TIMEDOUT = 0x1000,
+ SAISPRF_TERMINATED = 0x2000,
+ SAISPRF_EXIT = 0x8000,
+ SAISPRF_SIGNALLED = 0x4000,
};
typedef struct sais_sqlite_cache {
- lws_dll2_t list;
- char uuid[65];
- sqlite3 *pdb;
- lws_usec_t idle_since;
- int refcount;
+ lws_dll2_t list;
+ char uuid[65];
+ sqlite3 *pdb;
+ lws_usec_t idle_since;
+ int refcount;
} sais_sqlite_cache_t;
/* The top-level load report message from a builder */
typedef struct sai_active_task_info {
- lws_dll2_t list;
- char task_uuid[65];
- char task_name[96];
- int build_step;
- int total_steps;
- unsigned int est_peak_mem_kib;
- unsigned int est_disk_kib;
- uint64_t started;
+ lws_dll2_t list;
+ char task_uuid[65];
+ char task_name[96];
+ int build_step;
+ int total_steps;
+ unsigned int est_peak_mem_kib;
+ unsigned int est_disk_kib;
+ uint64_t started;
} sai_active_task_info_t;
typedef struct sai_load_report {
- lws_dll2_t list; /* For queuing on sai_plat_server */
- char builder_name[64];
- int core_count;
- unsigned int initial_free_ram_kib;
- unsigned int reserved_ram_kib;
- unsigned int initial_free_disk_kib;
- unsigned int reserved_disk_kib;
- unsigned int active_steps;
- unsigned int cpu_percent;
- lws_dll2_owner_t active_tasks;
+ lws_dll2_t list; /* For queuing on sai_plat_server */
+ char builder_name[64];
+ int core_count;
+ unsigned int initial_free_ram_kib;
+ unsigned int reserved_ram_kib;
+ unsigned int initial_free_disk_kib;
+ unsigned int reserved_disk_kib;
+ unsigned int active_steps;
+ unsigned int cpu_percent;
+ lws_dll2_owner_t active_tasks;
} sai_load_report_t;
/*
@@ -100,14 +100,14 @@ typedef struct sai_load_report {
* Sent from server -> builder.
*/
typedef struct sai_viewer_state {
- lws_dll2_t list; /* Not used, for schema mapping */
- unsigned int viewers;
+ lws_dll2_t list; /* Not used, for schema mapping */
+ unsigned int viewers;
} sai_viewer_state_t;
typedef struct sai_platform_load {
- lws_dll2_t list; /* Not used, for schema mapping */
- char platform_name[128];
- lws_dll2_owner_t loads;
+ lws_dll2_t list; /* Not used, for schema mapping */
+ char platform_name[128];
+ lws_dll2_owner_t loads;
} sai_platform_load_t;
@@ -116,64 +116,64 @@ struct sai_nspawn;
typedef struct sai_plat sai_plat_t;
typedef struct {
- lws_dll2_t list; /* managed by an owner via LSM_SCHEMA_DLL2 / lsm_task */
- lws_dll2_t pending_assign_list;
-
- const struct sai_event *one_event; /* event we are associated with */
-
- char platform[96];
- char build[4096]; /* strsubst and serialized */
- char taskname[96];
- char packages[2048];
- char artifacts[256];
- char prep[4096]; /* only build is serialized */
- char cmake[4096]; /* only build is serialized */
- char builder[65 + 5];
- char event_uuid[65];
- char art_up_nonce[33];
- char art_down_nonce[33];
- char uuid[65];
- char builder_name[96];
- char cpack[512];
- char script[4096];
- char branches[256];
-
- struct lwsac *ac_task_container;
-
- const char *server_name; /* used in offer */
- const char *repo_name; /* used in offer */
- const char *git_ref; /* used in offer */
- const char *git_hash; /* used in offer */
- const char *git_repo_url; /* used in offer */
- uint64_t last_updated;
- uint64_t started;
- uint64_t duration;
- int state;
- int uid;
- int build_step;
- int build_step_count;
+ lws_dll2_t list; /* managed by an owner via LSM_SCHEMA_DLL2 / lsm_task */
+ lws_dll2_t pending_assign_list;
+
+ const struct sai_event *one_event; /* event we are associated with */
+
+ char platform[96];
+ char build[4096]; /* strsubst and serialized */
+ char taskname[96];
+ char packages[2048];
+ char artifacts[256];
+ char prep[4096]; /* only build is serialized */
+ char cmake[4096]; /* only build is serialized */
+ char builder[65 + 5];
+ char event_uuid[65];
+ char art_up_nonce[33];
+ char art_down_nonce[33];
+ char uuid[65];
+ char builder_name[96];
+ char cpack[512];
+ char script[4096];
+ char branches[256];
+
+ struct lwsac *ac_task_container;
+
+ const char *server_name; /* used in offer */
+ const char *repo_name; /* used in offer */
+ const char *git_ref; /* used in offer */
+ const char *git_hash; /* used in offer */
+ const char *git_repo_url; /* used in offer */
+ uint64_t last_updated;
+ uint64_t started;
+ uint64_t duration;
+ int state;
+ int uid;
+ int build_step;
+ int build_step_count;
/* estimations for builder resource consumption */
- unsigned int est_peak_mem_kib;
- unsigned int est_disk_kib;
- unsigned int est_wallclock_ms;
- unsigned int est_compute_ms;
+ unsigned int est_peak_mem_kib;
+ unsigned int est_disk_kib;
+ unsigned int est_wallclock_ms;
+ unsigned int est_compute_ms;
- int parallel;
- char told_ongoing;
+ int parallel;
+ char told_ongoing;
- char rebuildable;
+ char rebuildable;
} sai_task_t;
struct saib_logproxy {
- char sockpath[128];
- struct sai_nspawn *ns;
- int log_channel_idx;
+ char sockpath[128];
+ struct sai_nspawn *ns;
+ int log_channel_idx;
};
struct saib_resproxy {
- char sockpath[128];
- struct sai_nspawn *ns;
+ char sockpath[128];
+ struct sai_nspawn *ns;
};
struct sai_nspawn {
@@ -181,9 +181,7 @@ struct sai_nspawn {
char inp_vn[16];
char path[384];
char script_path[290];
- char pending_mirror_log[128];
- /* convenient place to store it */
struct saib_logproxy slp_control;
struct saib_logproxy slp[2];
struct lws_vhost *vhosts[3];
@@ -398,53 +396,53 @@ struct sai_plat;
*/
typedef struct sai_plat_server {
- lws_dll2_t list;
+ lws_dll2_t list;
- lws_dll2_owner_t resource_pss_list; /* so we can find the cookie */
+ lws_dll2_owner_t resource_pss_list; /* so we can find the cookie */
- struct lws_buflist *bl_to_srv;
+ struct lws_buflist *bl_to_srv;
- char resproxy_path[128];
+ char resproxy_path[128];
/* for load reporting */
- lws_sorted_usec_list_t sul_load_report;
- unsigned int viewer_count;
+ lws_sorted_usec_list_t sul_load_report;
+ unsigned int viewer_count;
- const char *url;
- const char *name;
+ const char *url;
+ const char *name;
- struct lws_ss_handle *ss;
- void *opaque_data;
+ struct lws_ss_handle *ss;
+ void *opaque_data;
- lws_dll2_t *last_logging_nspawn;
- struct sai_plat *last_logging_platform;
+ lws_dll2_t *last_logging_nspawn;
+ struct sai_plat *last_logging_platform;
- int refcount;
+ int refcount;
- int index; /* used to create unique build dir path */
+ int index; /* used to create unique build dir path */
- uint16_t retries;
+ uint16_t retries;
} sai_plat_server_t;
struct sai_env {
- lws_dll2_t list;
+ lws_dll2_t list;
- const char *name;
- const char *value;
+ const char *name;
+ const char *value;
};
typedef struct sai_plat_server_ref {
- lws_dll2_t list;
- sai_plat_server_t *spm;
- char was_active;
+ lws_dll2_t list;
+ sai_plat_server_t *spm;
+ char was_active;
} sai_plat_server_ref_t;
/* common struct for lists of task uuids on a builder */
typedef struct sai_uuid_list {
- lws_dll2_t list;
- lws_usec_t us_time_listed;
- char uuid[65];
- char started;
+ lws_dll2_t list;
+ lws_usec_t us_time_listed;
+ char uuid[65];
+ char started;
} sai_uuid_list_t;
/*
@@ -491,59 +489,59 @@ typedef struct sai_uuid_list {
*/
typedef struct sai_plat {
- lws_dll2_t sai_plat_list;
+ lws_dll2_t sai_plat_list;
- lws_dll2_owner_t servers; /* list of sai_plat_server_ref_t */
+ lws_dll2_owner_t servers; /* list of sai_plat_server_ref_t */
- lws_sorted_usec_list_t sul_find_jobs; /* server */
+ lws_sorted_usec_list_t sul_find_jobs; /* server */
- char peer_ip[48];
+ char peer_ip[48];
- const char *name;
- const char *platform;
-
- struct lejp_ctx ctx;
- lws_dll2_owner_t nspawn_owner;
- struct lwsac *deserialization_ac;
+ const char *name;
+ const char *platform;
- struct lws_context *cx;
- struct lws *wsi; /* server side only */
- void *vhd;
+ struct lejp_ctx ctx;
+ lws_dll2_owner_t nspawn_owner;
+ struct lwsac *deserialization_ac;
- lws_dll2_owner_t env_head;
- char sai_hash[41];
- char lws_hash[41];
- uint64_t uid;
- lws_dll2_owner_t loads;
- int online; /* 1 = connected, 0 = offline */
- uint64_t last_seen; /* unix time */
- int powering_up; /* 1 = sai-power is booting it */
- int powering_down;
- unsigned int job_limit;
+ struct lws_context *cx;
+ struct lws *wsi; /* server side only */
+ void *vhd;
+
+ lws_dll2_owner_t env_head;
+ char sai_hash[41];
+ char lws_hash[41];
+ uint64_t uid;
+ lws_dll2_owner_t loads;
+ int online; /* 1 = connected, 0 = offline */
+ uint64_t last_seen; /* unix time */
+ int powering_up; /* 1 = sai-power is booting it */
+ int powering_down;
+ unsigned int job_limit;
/* server side only: builder resource tracking */
- lws_dll2_owner_t inflight_owner; /* sai_uuid_list_t */
- int avail_slots;
- unsigned int avail_mem_kib;
- unsigned int avail_sto_kib;
+ lws_dll2_owner_t inflight_owner; /* sai_uuid_list_t */
+ int avail_slots;
+ unsigned int avail_mem_kib;
+ unsigned int avail_sto_kib;
- char windows;
- char power_managed;
- char stay_on;
- char busy;
+ char windows;
+ char power_managed;
+ char stay_on;
+ char busy;
- int index; /* used to create unique build dir path */
+ int index; /* used to create unique build dir path */
} sai_plat_t;
typedef struct sai_plat_owner {
- lws_dll2_owner_t plat_owner;
+ lws_dll2_owner_t plat_owner;
} sai_plat_owner_t;
typedef struct sai_repo {
- char *name;
- char *fetch_url;
- char *notification_key;
+ char *name;
+ char *fetch_url;
+ char *notification_key;
} sai_repo_t;
typedef enum {
@@ -551,42 +549,42 @@ typedef enum {
} sai_log_action_t;
typedef struct sai_browse_rx_evinfo {
- char event_hash[65];
- int state;
+ char event_hash[65];
+ int state;
} sai_browse_rx_evinfo_t;
typedef struct sai_browse_rx_taskinfo {
- char task_hash[65];
- uint64_t last_log_ts;
- unsigned int log_start;
- unsigned int js_api_version;
- uint8_t logs;
+ char task_hash[65];
+ uint64_t last_log_ts;
+ unsigned int log_start;
+ unsigned int js_api_version;
+ uint8_t logs;
} sai_browse_rx_taskinfo_t;
/* sai-power -> sai-server, tells it that a platform is being powered up */
typedef struct sai_power_state {
- lws_dll2_t list; /* for parser */
- char host[256];
- int powering_up;
- int powering_down;
+ lws_dll2_t list; /* for parser */
+ char host[256];
+ int powering_up;
+ int powering_down;
} sai_power_state_t;
typedef struct sai_build_metric {
- lws_dll2_t list;
- char key[65];
- char task_uuid[65];
- char builder_name[96];
- char project_name[96];
- char ref[96];
- uint64_t unixtime;/* actually autoincrement index in sql3 */
- uint64_t unix_time;
- uint64_t us_cpu_user;
- uint64_t us_cpu_sys;
- uint64_t wallclock_us;
- uint64_t peak_mem_rss;
- uint64_t stg_bytes;
- int parallel;
- int step;
+ lws_dll2_t list;
+ char key[65];
+ char task_uuid[65];
+ char builder_name[96];
+ char project_name[96];
+ char ref[96];
+ uint64_t unixtime;/* actually autoincrement index in sql3 */
+ uint64_t unix_time;
+ uint64_t us_cpu_user;
+ uint64_t us_cpu_sys;
+ uint64_t wallclock_us;
+ uint64_t peak_mem_rss;
+ uint64_t stg_bytes;
+ int parallel;
+ int step;
} sai_build_metric_t;
/*
@@ -596,42 +594,42 @@ typedef struct sai_build_metric {
* power down automatically when idle.
*/
typedef struct sai_stay {
- lws_dll2_t list;
- char builder_name[64];
- char stay_on; /* 0 = release, 1 = set */
+ lws_dll2_t list;
+ char builder_name[64];
+ char stay_on; /* 0 = release, 1 = set */
} sai_stay_t;
typedef struct sai_controlled_builder {
- lws_dll2_t list;
- char name[64];
+ lws_dll2_t list;
+ char name[64];
} sai_controlled_builder_t;
/* sai-power -> sai-server, tells it about power controllers */
typedef struct sai_power_controller {
- lws_dll2_t list;
- lws_dll2_owner_t controlled_builders_owner;
- char name[64];
- char on;
+ lws_dll2_t list;
+ lws_dll2_owner_t controlled_builders_owner;
+ char name[64];
+ char on;
} sai_power_controller_t;
/* sai-power -> sai-server, tells it the builders it can manage */
typedef struct sai_power_managed_builder {
- lws_dll2_t list;
- char name[64];
- char stay_on;
+ lws_dll2_t list;
+ char name[64];
+ char stay_on;
} sai_power_managed_builder_t;
typedef struct sai_power_managed_builders {
- lws_dll2_t list;
- lws_dll2_owner_t builders; /* sai_power_managed_builder_t */
- lws_dll2_owner_t power_controllers; /* sai_power_controller_t */
+ lws_dll2_t list;
+ lws_dll2_owner_t builders; /* sai_power_managed_builder_t */
+ lws_dll2_owner_t power_controllers; /* sai_power_controller_t */
} sai_power_managed_builders_t;
typedef struct sai_stay_state_update {
- lws_dll2_t list;
- char builder_name[64];
- char stay_on;
+ lws_dll2_t list;
+ char builder_name[64];
+ char stay_on;
} sai_stay_state_update_t;
/*
diff --git a/src/power/p-private.h b/src/power/p-private.h
index 332f94e..1d92458 100644
--- a/src/power/p-private.h
+++ b/src/power/p-private.h
@@ -128,8 +128,6 @@ struct sai_power {
struct lws_context *context;
struct lws_vhost *vhost;
- struct sai_nspawn wol_nspawn;
-
lws_sorted_usec_list_t sul_idle;
const char *power_off;
diff --git a/src/power/p-sai.c b/src/power/p-sai.c
index d5120bc..e7932b9 100644
--- a/src/power/p-sai.c
+++ b/src/power/p-sai.c
@@ -413,12 +413,10 @@ int main(int argc, const char **argv)
realpath(argv[0], rpath);
memset(&info, 0, sizeof(info));
- memset(&power.wol_nspawn, 0, sizeof(power.wol_nspawn));
info.vh = power.vhost;
info.exec_array = ea;
info.max_log_lines = 100;
- info.opaque = (void *)&power.wol_nspawn;
info.protocol_name = "protocol_std";
lsp_wol = lws_spawn_piped(&info);
diff --git a/src/power/p-smartplug.c b/src/power/p-smartplug.c
index af6faf5..02d1f21 100644
--- a/src/power/p-smartplug.c
+++ b/src/power/p-smartplug.c
@@ -70,7 +70,7 @@ saip_ss_create_tasmota()
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) {
+ if (pc->type && !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,
diff --git a/src/power/p-ws-server.c b/src/power/p-ws-server.c
index 016240f..0b8b345 100644
--- a/src/power/p-ws-server.c
+++ b/src/power/p-ws-server.c
@@ -97,7 +97,7 @@ saip_queue_stay_info(saip_server_t *sps)
saip_pcon_t *pc = lws_container_of(p, saip_pcon_t, list);
sai_power_controller_t *pc1 = lwsac_use_zero(&ac, sizeof(*pc1), 2048);
- if (pc1) {
+ if (pc1 && pc->name) {
lws_strncpy(pc1->name, pc->name, sizeof(pc1->name));
pc1->on = pc->on;
diff --git a/src/server/s-task-helpers.c b/src/server/s-task-helpers.c
index d78ab29..5efe89c 100644
--- a/src/server/s-task-helpers.c
+++ b/src/server/s-task-helpers.c
@@ -217,8 +217,9 @@ sais_set_task_state(struct vhd *vhd, const char *task_uuid,
if (started) {
if (started == 1)
- started = 0;
- lws_snprintf(esc3, sizeof(esc3), ",started=%llu",
+ lws_snprintf(esc3, sizeof(esc3), ",started=0");
+ else
+ lws_snprintf(esc3, sizeof(esc3), ",started=%llu",
(unsigned long long)started);
}
if (duration) {
diff --git a/src/server/s-ws-builder.c b/src/server/s-ws-builder.c
index ae5b599..2feed99 100644
--- a/src/server/s-ws-builder.c
+++ b/src/server/s-ws-builder.c
@@ -499,8 +499,10 @@ sais_process_rej(struct vhd *vhd, struct pss *pss,
sai_task_uuid_to_event_uuid(event_uuid, rej->task_uuid);
if (sai_event_db_ensure_open(vhd->context, &vhd->sqlite3_cache,
- vhd->sqlite3_path_lhs, event_uuid, 0, &pdb))
+ vhd->sqlite3_path_lhs, event_uuid, 0, &pdb)) {
+ lwsl_err("%s: unable to open db for event %s\n", __func__, event_uuid);
break;
+ }
lws_sql_purify(esc_uuid, rej->task_uuid, sizeof(esc_uuid));
lws_snprintf(q, sizeof(q),
@@ -522,12 +524,17 @@ sais_process_rej(struct vhd *vhd, struct pss *pss,
build_step, esc_uuid);
sqlite3_exec(pdb, q, NULL, NULL, NULL);
+ lwsl_notice("%s: &&&&&&&& build_step set to %d\n", __func__, build_step);
+
if (build_step == 1) {
pss->first_log_timestamp = (uint64_t)lws_now_secs();
lws_snprintf(q, sizeof(q),
"update tasks set started=%llu where uuid='%s'",
(unsigned long long)pss->first_log_timestamp, esc_uuid);
+ lwsl_warn("%s: &&&&&&&&&&&&&&&&&&&&&&&&&& setting task %s started to %llu\n",
+ __func__, esc_uuid, (unsigned long long)pss->first_log_timestamp);
+
if (sqlite3_exec(pdb, q, NULL, NULL, NULL) != SQLITE_OK)
lwsl_notice("%s: unable to set started\n", __func__);
}