Merge pull request #24 from multica-ai/ldnvnbl/hub-gateway-config

Add gateway URL configuration to Hub Console
This commit is contained in:
LinYushen 2026-01-30 11:01:39 +08:00 committed by GitHub
commit 1bf2b47fca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 61 additions and 9 deletions

View file

@ -2,6 +2,7 @@ import {
Controller,
Get,
Post,
Put,
Delete,
Param,
Body,
@ -23,6 +24,15 @@ export class AppController {
};
}
@Put("hub/gateway")
updateGateway(@Body() body: { url: string }) {
this.hub.reconnect(body.url);
return {
url: this.hub.url,
connectionState: this.hub.connectionState,
};
}
@Get("agents")
listAgents() {
return this.hub.listAgents().map((id) => {

View file

@ -15,6 +15,9 @@
.agent-list { list-style: none; }
.agent-list li { display: flex; justify-content: space-between; align-items: center; padding: 0.6rem 0; border-bottom: 1px solid #222; font-family: monospace; font-size: 0.85rem; }
.agent-list li:last-child { border-bottom: none; }
.gateway-form { display: flex; gap: 0.5rem; align-items: center; margin-top: 0.8rem; }
.gateway-form input { background: #0a0a0a; color: #e0e0e0; border: 1px solid #444; border-radius: 4px; padding: 0.4rem 0.6rem; font-size: 0.85rem; font-family: monospace; flex: 1; }
.gateway-form input:focus { outline: none; border-color: #666; }
button { background: #2a2a2a; color: #e0e0e0; border: 1px solid #444; border-radius: 4px; padding: 0.4rem 0.8rem; cursor: pointer; font-size: 0.8rem; }
button:hover { background: #3a3a3a; }
.btn-create { background: #1a3a1a; border-color: #2a5a2a; }
@ -30,6 +33,10 @@
<div class="card">
<h2>Hub Status</h2>
<div class="hub-info" id="hub-info">Loading...</div>
<div class="gateway-form">
<input type="text" id="gateway-url" placeholder="Gateway URL">
<button class="btn-create" onclick="updateGateway()">Connect</button>
</div>
</div>
<div class="card">
@ -56,6 +63,11 @@
`<span>State: <b style="color:${stateColor}">${hubRes.connectionState}</b></span>` +
`<span>Agents: <b>${hubRes.agentCount}</b></span>`;
const input = document.getElementById('gateway-url');
if (!input.dataset.edited) {
input.value = hubRes.url;
}
const list = document.getElementById('agent-list');
if (agentsRes.length === 0) {
list.innerHTML = '<li class="empty">No agents</li>';
@ -66,6 +78,23 @@
}
}
document.getElementById('gateway-url').addEventListener('input', function() {
this.dataset.edited = '1';
});
async function updateGateway() {
const input = document.getElementById('gateway-url');
const url = input.value.trim();
if (!url) return;
await fetch(`${API}/hub/gateway`, {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ url }),
});
input.dataset.edited = '';
refresh();
}
async function createAgent() {
await fetch(`${API}/agents`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' });
refresh();

View file

@ -7,8 +7,8 @@ import { GatewayClient } from "../shared/gateway-sdk/client.js";
export class Hub {
private readonly agents = new Map<string, Agent>();
private readonly agentSenders = new Map<string, string>();
private readonly client: GatewayClient;
readonly url: string;
private client: GatewayClient;
url: string;
readonly path: string;
readonly deviceId: string;
@ -21,9 +21,13 @@ export class Hub {
this.url = url;
this.path = path ?? "/ws";
this.deviceId = getDeviceId();
this.client = this.createClient(this.url);
this.client.connect();
}
this.client = new GatewayClient({
url: this.url,
private createClient(url: string): GatewayClient {
const client = new GatewayClient({
url,
path: this.path,
deviceId: this.deviceId,
deviceType: "client",
@ -31,19 +35,19 @@ export class Hub {
reconnectDelay: 1000,
});
this.client.onStateChange((state) => {
client.onStateChange((state) => {
console.log(`[Hub] Connection state: ${state}`);
});
this.client.onRegistered((deviceId) => {
client.onRegistered((deviceId) => {
console.log(`[Hub] Registered as: ${deviceId}`);
});
this.client.onError((err) => {
client.onError((err) => {
console.error(`[Hub] Connection error:`, err.message);
});
this.client.onMessage((msg) => {
client.onMessage((msg) => {
console.log(`[Hub] Received message: id=${msg.id} from=${msg.from} to=${msg.to} action=${msg.action} payload=${JSON.stringify(msg.payload)}`);
const payload = msg.payload as { agentId?: string; content?: string } | undefined;
const agentId = payload?.agentId;
@ -61,10 +65,19 @@ export class Hub {
}
});
this.client.onSendError((err) => {
client.onSendError((err) => {
console.error(`[Hub] Send error: messageId=${err.messageId} code=${err.code} error=${err.error}`);
});
return client;
}
/** 重连到新的 Gateway 地址 */
reconnect(url: string): void {
console.log(`[Hub] Reconnecting to ${url}`);
this.client.disconnect();
this.url = url;
this.client = this.createClient(url);
this.client.connect();
}