Skip to content
This repository was archived by the owner on Jun 24, 2026. It is now read-only.

Commit 765f3ff

Browse files
feat: update @ratiosolver/coco to version 0.0.85; enhance MQTT configuration with maximum buffered messages and improve item handling in ItemsTable
1 parent eba6ddb commit 765f3ff

9 files changed

Lines changed: 62 additions & 58 deletions

File tree

CMakeLists.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ endif()
3636
if(BUILD_MQTT)
3737
option(MQTT_SECURE "Build MQTT secure connection" OFF)
3838
option(MQTT_AUTH "Build MQTT authentication" OFF)
39+
set(MQTT_MAX_BUFFERED_MSGS 100 CACHE STRING "Maximum buffered messages when offline")
3940
endif()
4041

4142
if(BUILD_LLM)
@@ -71,7 +72,9 @@ message(STATUS "Build CoCo server: ${BUILD_COCO_SERVER}")
7172
message(STATUS "Build Firebase Cloud Messaging: ${BUILD_FCM}")
7273
message(STATUS "Build MQTT middleware: ${BUILD_MQTT}")
7374
if(BUILD_MQTT)
75+
message(STATUS "Build MQTT secure connection: ${MQTT_SECURE}")
7476
message(STATUS "Build MQTT authentication: ${MQTT_AUTH}")
77+
message(STATUS "MQTT maximum buffered messages when offline: ${MQTT_MAX_BUFFERED_MSGS}")
7578
endif()
7679
message(STATUS "Build CoCo LLM: ${BUILD_LLM}")
7780
if(BUILD_COCO_SERVER)
@@ -149,7 +152,7 @@ if(BUILD_MQTT)
149152
target_include_directories(CoCo PUBLIC ${PAHO_MQTT_CPP_INCLUDE_DIR} $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mqtt>)
150153
target_sources(CoCo PRIVATE src/mqtt/coco_mqtt.cpp)
151154
target_link_libraries(CoCo PUBLIC PahoMqttCpp::paho-mqttpp3)
152-
target_compile_definitions(CoCo PUBLIC BUILD_LISTENERS BUILD_MQTT)
155+
target_compile_definitions(CoCo PUBLIC BUILD_LISTENERS BUILD_MQTT MQTT_MAX_BUFFERED_MSGS=${MQTT_MAX_BUFFERED_MSGS})
153156

154157
if(MQTT_AUTH)
155158
target_compile_definitions(CoCo PUBLIC MQTT_AUTH)

gui/app/package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gui/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"vite": "^6.2.0"
1515
},
1616
"dependencies": {
17-
"@ratiosolver/coco": "^0.0.84",
17+
"@ratiosolver/coco": "^0.0.85",
1818
"@ratiosolver/flick": "^0.1.12",
1919
"@ratiosolver/solver": "^0.0.42",
2020
"bootstrap": "^5.3.6"

gui/coco/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gui/coco/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@ratiosolver/coco",
3-
"version": "0.0.84",
3+
"version": "0.0.85",
44
"type": "module",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

gui/coco/src/coco/coco.ts

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ export namespace coco {
193193
if (itm.types)
194194
for (const tn of itm.types)
195195
types.add(this.get_type(tn)!);
196-
return new taxonomy.Item(id, types, itm.properties, value, (itm as any).slots);
196+
return new taxonomy.Item(id, types, itm.properties, value);
197197
}
198198

199199
get_type(name: string): taxonomy.Type { return this.types.get(name)!; }
@@ -565,27 +565,24 @@ export namespace coco {
565565
private readonly types: Set<Type> = new Set();
566566
private properties?: Record<string, unknown>;
567567
private datum?: Datum;
568-
private slots?: Record<string, unknown>;
569568
private data: Datum[] = [];
570569
private readonly listeners = new Set<ItemListener>();
571570

572-
constructor(id: string, types: Set<Type>, properties?: Record<string, unknown>, value?: Datum, slots?: Record<string, unknown>) {
571+
constructor(id: string, types: Set<Type>, properties?: Record<string, unknown>, value?: Datum) {
573572
this.id = id;
574573
for (const tp of types) {
575574
this.types.add(tp);
576575
tp._instances.add(this);
577576
}
578577
this.properties = properties;
579578
this.datum = value;
580-
this.slots = slots;
581579
}
582580

583581
get_id(): string { return this.id; }
584582
get_types(): Set<Type> { return this.types; }
585583
get_properties(): Record<string, unknown> | undefined { return this.properties; }
586584
get_datum(): Datum | undefined { return this.datum; }
587585
get_data(): Datum[] { return this.data; }
588-
get_slots(): Record<string, unknown> | undefined { return this.slots; }
589586

590587
_set_types(types: Set<Type>): void {
591588
for (const tp of this.types)
@@ -610,10 +607,6 @@ export namespace coco {
610607
this.data.push(datum);
611608
for (const l of this.listeners) l.new_value(this, datum);
612609
}
613-
_set_slots(slots?: Record<string, unknown>): void {
614-
this.slots = slots;
615-
for (const l of this.listeners) l.slots_updated(this);
616-
}
617610

618611
add_item_listener(l: ItemListener): void { this.listeners.add(l); }
619612
remove_item_listener(l: ItemListener): void { this.listeners.delete(l); }
@@ -627,7 +620,6 @@ export namespace coco {
627620
properties_updated(item: Item): void;
628621
values_updated(item: Item): void;
629622
new_value(item: Item, v: Datum): void;
630-
slots_updated(item: Item): void;
631623
}
632624

633625
export function get_static_properties(item: Item): Map<string, Property<unknown>> {
@@ -707,26 +699,6 @@ export namespace coco {
707699
get_type(): EntityType { return this.type; }
708700
get_description(): string { return this.description; }
709701
}
710-
711-
export class Slot {
712-
713-
private readonly name: string;
714-
private readonly type: EntityType;
715-
private readonly description: string;
716-
private readonly influence_context: boolean;
717-
718-
constructor(name: string, type: EntityType, description: string, influence_context: boolean) {
719-
this.name = name;
720-
this.type = type;
721-
this.description = description;
722-
this.influence_context = influence_context;
723-
}
724-
725-
get_name(): string { return this.name; }
726-
get_type(): EntityType { return this.type; }
727-
get_description(): string { return this.description; }
728-
is_influencing_context(): boolean { return this.influence_context; }
729-
}
730702
}
731703
}
732704

gui/coco/src/coco/components/items_table.ts

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
1-
import { App, PayloadComponent } from "@ratiosolver/flick";
1+
import { App, blink, PayloadComponent } from "@ratiosolver/flick";
22
import { coco } from "../coco";
33
import { Item } from "./item";
44

5-
export class ItemsTable extends PayloadComponent<HTMLDivElement, coco.taxonomy.Item[]> implements coco.CoCoListener {
5+
export class ItemsTable extends PayloadComponent<HTMLDivElement, coco.taxonomy.Item[]> implements coco.CoCoListener, coco.taxonomy.ItemListener {
66

77
private readonly type: coco.taxonomy.Type;
88
private readonly tbody: HTMLTableSectionElement;
9+
private readonly items: Map<string, HTMLTableRowElement> = new Map();
10+
private readonly static_props: Map<string, coco.taxonomy.Property<unknown>> | undefined
911

1012
constructor(type: coco.taxonomy.Type, items: coco.taxonomy.Item[] = Array.from(type.get_instances())) {
1113
super(document.createElement("div"), items);
1214
this.type = type;
15+
this.static_props = type.get_static_properties();
1316

1417
const table = document.createElement("table");
1518
table.classList.add("table", "table-hover", 'caption-top');
@@ -41,19 +44,52 @@ export class ItemsTable extends PayloadComponent<HTMLDivElement, coco.taxonomy.I
4144

4245
new_type(_: coco.taxonomy.Type): void { }
4346
new_item(item: coco.taxonomy.Item): void {
44-
if (item.get_types().has(this.type))
47+
if (item.get_types().has(this.type)) {
4548
this.add_item(item);
49+
item.add_item_listener(this);
50+
}
4651
}
4752

53+
types_updated(item: coco.taxonomy.Item): void {
54+
if (item.get_types().has(this.type)) {
55+
if (!this.items.has(item.get_id()))
56+
this.new_item(item);
57+
} else {
58+
const row = this.items.get(item.get_id());
59+
if (row) {
60+
this.tbody.removeChild(row);
61+
this.items.delete(item.get_id());
62+
item.remove_item_listener(this);
63+
}
64+
}
65+
}
66+
properties_updated(item: coco.taxonomy.Item): void {
67+
const row = this.items.get(item.get_id());
68+
if (row && this.static_props) {
69+
const item_props = item.get_properties();
70+
let col_idx = 1;
71+
for (const [prop_name, prop] of this.static_props) {
72+
const td = row.children.item(col_idx) as HTMLTableCellElement;
73+
if (item_props && item_props[prop_name] !== undefined)
74+
td.textContent = prop.get_type().to_string(item_props[prop_name]);
75+
else
76+
td.textContent = "";
77+
col_idx += 1;
78+
}
79+
blink(row);
80+
}
81+
}
82+
values_updated(_item: coco.taxonomy.Item): void { }
83+
new_value(_item: coco.taxonomy.Item, _v: coco.taxonomy.Datum): void { }
84+
4885
private add_item(item: coco.taxonomy.Item) {
49-
const static_props = this.type.get_static_properties();
5086
const row = document.createElement("tr");
5187
row.style.cursor = "pointer";
5288
const id_td = document.createElement("td");
5389
id_td.textContent = item.get_id();
5490
row.appendChild(id_td);
55-
if (static_props)
56-
for (const [prop_name, prop] of static_props) {
91+
if (this.static_props)
92+
for (const [prop_name, prop] of this.static_props) {
5793
const td = document.createElement("td");
5894
const item_props = item.get_properties();
5995
if (item_props && item_props[prop_name] !== undefined)
@@ -63,6 +99,7 @@ export class ItemsTable extends PayloadComponent<HTMLDivElement, coco.taxonomy.I
6399
row.appendChild(td);
64100
}
65101
row.addEventListener("click", () => App.get_instance().selected_component(new Item(item)));
102+
this.items.set(item.get_id(), row);
66103
this.tbody.appendChild(row);
67104
}
68105

include/mqtt/coco_mqtt.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
namespace coco
1414
{
15-
constexpr const int QOS = 1; // Quality of Service level for MQTT messages
15+
constexpr const int QOS = 1; // Quality of Service level for MQTT messages
1616

1717
[[nodiscard]] inline std::string default_mqtt_uri() noexcept
1818
{

src/mqtt/coco_mqtt.cpp

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55

66
namespace coco
77
{
8-
coco_mqtt::coco_mqtt(coco &cc, std::string_view mqtt_uri, std::string_view client_id) noexcept : coco_module(cc), listener(cc), client(mqtt_uri.data(), client_id.data())
8+
coco_mqtt::coco_mqtt(coco &cc, std::string_view mqtt_uri, std::string_view client_id) noexcept : coco_module(cc), listener(cc), client(mqtt_uri.data(), client_id.data(), MQTT_MAX_BUFFERED_MSGS)
99
{
1010
conn_opts.set_keep_alive_interval(20);
1111
conn_opts.set_clean_session(true);
12+
conn_opts.set_automatic_reconnect(true);
1213
conn_opts.set_mqtt_version(MQTTVERSION_5);
1314
#ifdef MQTT_AUTH
1415
LOG_DEBUG("Setting MQTT authentication");
@@ -55,26 +56,17 @@ namespace coco
5556

5657
mqtt::subscribe_options opts;
5758
opts.set_no_local(true); // Prevent receiving messages from self
59+
[[maybe_unused]] size_t item_count = 0;
5860
for (auto &itm : get_coco().get_items())
5961
{
62+
LOG_TRACE("Subscribing/publishing item " << ++item_count << "/" << get_coco().get_items().size());
6063
client.publish(COCO_NAME "/items/" + itm.get().get_id(), itm.get().to_json().dump(), QOS, true); // Publish each item
6164
client.subscribe(COCO_NAME "/data/" + itm.get().get_id(), QOS, opts); // Subscribe to data updates for each item
6265
}
6366
}
6467
void coco_mqtt::on_connection_lost(const std::string &cause)
6568
{
6669
LOG_ERR("Connection lost: " << cause);
67-
std::this_thread::sleep_for(std::chrono::milliseconds(2500));
68-
LOG_DEBUG("Reconnecting to MQTT broker...");
69-
try
70-
{
71-
client.connect(conn_opts);
72-
LOG_DEBUG("Reconnected to MQTT broker");
73-
}
74-
catch (const mqtt::exception &e)
75-
{
76-
LOG_ERR("Failed to reconnect: " << e.what());
77-
}
7870
}
7971

8072
void coco_mqtt::created_type(const type &tp)

0 commit comments

Comments
 (0)