Use SubscriptionController

This commit is contained in:
Danielv123 committed 2025-08-10 00:28:48 +02:00
1 parent 70ef8a60ad
commit 48437a5f6c
2 files changed
+74 -12

No files matched your search

+15 -11
View File
@@ -98,6 +98,7 @@ export class ControllerPlugin extends BaseControllerPlugin {
await fs.ensureDir(this.recipeTilesPath);
await fs.ensureDir(this.playerPositionsPath);
// Handle incoming events from instances
this.controller.handle(TileDataEvent, this.handleTileDataEvent.bind(this));
this.controller.handle(ChartTagDataEvent, this.handleChartTagDataEvent.bind(this));
this.controller.handle(GetRawTileRequest, this.handleGetRawTileRequest.bind(this));
@@ -107,6 +108,12 @@ export class ControllerPlugin extends BaseControllerPlugin {
this.controller.handle(PlayerPositionEvent, this.handlePlayerPositionEvent.bind(this));
this.controller.handle(GetPlayerPathRequest, this.handleGetPlayerPathRequest.bind(this));
// Register events as subscribable for web clients
this.controller.subscriptions.handle(TileDataEvent);
this.controller.subscriptions.handle(ChartTagDataEvent);
this.controller.subscriptions.handle(RecipeDataEvent);
this.controller.subscriptions.handle(PlayerPositionEvent);
// Set up HTTP routes for serving tiles
this.setupTileRoutes();
@@ -750,11 +757,10 @@ export class ControllerPlugin extends BaseControllerPlugin {
// Queue for batch saving
this.chartTagQueues.get(fileKey)!.push(enrichedTagData);
// Send live update to connected web clients
const updateEvent = new ChartTagDataEvent(instance_id, tag_data);
// Broadcast to web clients
this.controller.sendTo(new lib.Address(lib.Address.broadcast, lib.Address.control), updateEvent);
// Broadcast to subscribed web clients only
this.controller.subscriptions.broadcast(updateEvent);
} catch (err) {
this.logger.error(`Error processing chart tag data: ${err}`);
@@ -780,7 +786,6 @@ export class ControllerPlugin extends BaseControllerPlugin {
}
this.chunkSavingQueue.get(tileName)!.set(chunkName, { data: chunk, tick });
// Send live update to connected web clients
const updateEvent = new TileDataEvent(
instance_id,
surface,
@@ -791,8 +796,8 @@ export class ControllerPlugin extends BaseControllerPlugin {
chunk
);
// Broadcast to web clients
this.controller.sendTo(new lib.Address(lib.Address.broadcast, lib.Address.control), updateEvent);
// Broadcast to subscribed web clients only
this.controller.subscriptions.broadcast(updateEvent);
} catch (err) {
this.logger.error(`Error processing tile data: ${err}`);
@@ -1009,8 +1014,8 @@ export class ControllerPlugin extends BaseControllerPlugin {
}
this.recipeSavingQueue.get(tileKey)!.push(...buffersToWrite);
// broadcast live update
this.controller.sendTo(new lib.Address(lib.Address.broadcast, lib.Address.control), event);
// Broadcast live update to subscribed web clients only
this.controller.subscriptions.broadcast(event);
} catch (err) {
this.logger.error(`Error processing recipe data: ${err}`);
@@ -1078,11 +1083,10 @@ export class ControllerPlugin extends BaseControllerPlugin {
// Queue for batch saving
this.playerPositionQueues.get(fileKey)!.push(enrichedPlayerData);
// Send live update to connected web clients
const updateEvent = new PlayerPositionEvent(instance_id, player_data);
// Broadcast to web clients
this.controller.sendTo(new lib.Address(lib.Address.broadcast, lib.Address.control), updateEvent);
// Broadcast to subscribed web clients only
this.controller.subscriptions.broadcast(updateEvent);
} catch (err) {
this.logger.error(`Error processing player position data: ${err}`);
+59 -1
View File
@@ -1,14 +1,19 @@
import React from "react";
import { BaseWebPlugin } from "@clusterio/web_ui";
import * as lib from "@clusterio/lib";
import CanvasMinimapPage from "./CanvasMinimapPage";
import { TileDataEvent, ChartTagDataEvent, RecipeDataEvent, PlayerPositionEvent } from "../messages";
export class WebPlugin extends BaseWebPlugin {
// Callback arrays for minimap updates
tileUpdateCallbacks: Array<(event: TileDataEvent) => void> = [];
chartTagUpdateCallbacks: Array<(event: ChartTagDataEvent) => void> = [];
recipeUpdateCallbacks: Array<(event: RecipeDataEvent) => void> = [];
playerPositionUpdateCallbacks: Array<(event: PlayerPositionEvent) => void> = [];
// Track subscription state
private subscribed = false;
async init() {
this.pages = [
{
@@ -19,13 +24,58 @@ export class WebPlugin extends BaseWebPlugin {
},
];
// Handle tile update events from the controller
// Handle minimap events from the controller
this.control.handle(TileDataEvent, this.handleTileDataEvent.bind(this));
this.control.handle(ChartTagDataEvent, this.handleChartTagDataEvent.bind(this));
this.control.handle(RecipeDataEvent, this.handleRecipeDataEvent.bind(this));
this.control.handle(PlayerPositionEvent, this.handlePlayerPositionEvent.bind(this));
}
onControllerConnectionEvent(event: "connect" | "drop" | "resume" | "close") {
if (event === "connect") {
this.updateSubscriptions();
}
}
private async updateSubscriptions() {
if (!this.control.connector.connected) {
return;
}
const shouldSubscribe = this.hasActiveCallbacks();
if (shouldSubscribe && !this.subscribed) {
// Subscribe to all minimap events
try {
await this.control.send(new lib.SubscriptionRequest("minimap:TileDataEvent", true));
await this.control.send(new lib.SubscriptionRequest("minimap:ChartTagDataEvent", true));
await this.control.send(new lib.SubscriptionRequest("minimap:RecipeDataEvent", true));
await this.control.send(new lib.SubscriptionRequest("minimap:PlayerPositionEvent", true));
this.subscribed = true;
} catch (err) {
this.logger.error(`Failed to subscribe to minimap events: ${err}`);
}
} else if (!shouldSubscribe && this.subscribed) {
// Unsubscribe from all minimap events
try {
await this.control.send(new lib.SubscriptionRequest("minimap:TileDataEvent", false));
await this.control.send(new lib.SubscriptionRequest("minimap:ChartTagDataEvent", false));
await this.control.send(new lib.SubscriptionRequest("minimap:RecipeDataEvent", false));
await this.control.send(new lib.SubscriptionRequest("minimap:PlayerPositionEvent", false));
this.subscribed = false;
} catch (err) {
this.logger.error(`Failed to unsubscribe from minimap events: ${err}`);
}
}
}
private hasActiveCallbacks(): boolean {
return this.tileUpdateCallbacks.length > 0
|| this.chartTagUpdateCallbacks.length > 0
|| this.recipeUpdateCallbacks.length > 0
|| this.playerPositionUpdateCallbacks.length > 0;
}
async handleTileDataEvent(event: TileDataEvent) {
// Notify all registered callbacks
for (let callback of this.tileUpdateCallbacks) {
@@ -53,6 +103,7 @@ export class WebPlugin extends BaseWebPlugin {
onTileUpdate(callback: (event: TileDataEvent) => void) {
this.tileUpdateCallbacks.push(callback);
this.updateSubscriptions();
}
offTileUpdate(callback: (event: TileDataEvent) => void) {
@@ -61,10 +112,12 @@ export class WebPlugin extends BaseWebPlugin {
throw new Error("callback is not registered");
}
this.tileUpdateCallbacks.splice(index, 1);
this.updateSubscriptions();
}
onChartTagUpdate(callback: (event: ChartTagDataEvent) => void) {
this.chartTagUpdateCallbacks.push(callback);
this.updateSubscriptions();
}
offChartTagUpdate(callback: (event: ChartTagDataEvent) => void) {
@@ -73,10 +126,12 @@ export class WebPlugin extends BaseWebPlugin {
throw new Error("callback is not registered");
}
this.chartTagUpdateCallbacks.splice(index, 1);
this.updateSubscriptions();
}
onRecipeUpdate(callback: (event: RecipeDataEvent) => void) {
this.recipeUpdateCallbacks.push(callback);
this.updateSubscriptions();
}
offRecipeUpdate(callback: (event: RecipeDataEvent) => void) {
@@ -85,10 +140,12 @@ export class WebPlugin extends BaseWebPlugin {
throw new Error("callback is not registered");
}
this.recipeUpdateCallbacks.splice(index, 1);
this.updateSubscriptions();
}
onPlayerPositionUpdate(callback: (event: PlayerPositionEvent) => void) {
this.playerPositionUpdateCallbacks.push(callback);
this.updateSubscriptions();
}
offPlayerPositionUpdate(callback: (event: PlayerPositionEvent) => void) {
@@ -97,5 +154,6 @@ export class WebPlugin extends BaseWebPlugin {
throw new Error("callback is not registered");
}
this.playerPositionUpdateCallbacks.splice(index, 1);
this.updateSubscriptions();
}
}