mirror of
https://github.com/samanhappy/mcphub.git
synced 2026-01-01 04:08:52 -05:00
feat: add group management functionality (#12)
This commit is contained in:
223
src/services/groupService.ts
Normal file
223
src/services/groupService.ts
Normal file
@@ -0,0 +1,223 @@
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { IGroup, McpSettings } from '../types/index.js';
|
||||
import { loadSettings, saveSettings } from '../config/index.js';
|
||||
import { notifyToolChanged } from './mcpService.js';
|
||||
|
||||
// Get all groups
|
||||
export const getAllGroups = (): IGroup[] => {
|
||||
const settings = loadSettings();
|
||||
return settings.groups || [];
|
||||
};
|
||||
|
||||
// Get group by ID
|
||||
export const getGroupById = (id: string): IGroup | undefined => {
|
||||
const groups = getAllGroups();
|
||||
return groups.find((group) => group.id === id);
|
||||
};
|
||||
|
||||
// Create a new group
|
||||
export const createGroup = (
|
||||
name: string,
|
||||
description?: string,
|
||||
servers: string[] = [],
|
||||
): IGroup | null => {
|
||||
try {
|
||||
const settings = loadSettings();
|
||||
const groups = settings.groups || [];
|
||||
|
||||
// Check if group with same name already exists
|
||||
if (groups.some((group) => group.name === name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Filter out non-existent servers
|
||||
const validServers = servers.filter((serverName) => settings.mcpServers[serverName]);
|
||||
|
||||
const newGroup: IGroup = {
|
||||
id: uuidv4(),
|
||||
name,
|
||||
description,
|
||||
servers: validServers,
|
||||
};
|
||||
|
||||
// Initialize groups array if it doesn't exist
|
||||
if (!settings.groups) {
|
||||
settings.groups = [];
|
||||
}
|
||||
|
||||
settings.groups.push(newGroup);
|
||||
|
||||
if (!saveSettings(settings)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return newGroup;
|
||||
} catch (error) {
|
||||
console.error('Failed to create group:', error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Update an existing group
|
||||
export const updateGroup = (id: string, data: Partial<IGroup>): IGroup | null => {
|
||||
try {
|
||||
const settings = loadSettings();
|
||||
if (!settings.groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const groupIndex = settings.groups.findIndex((group) => group.id === id);
|
||||
if (groupIndex === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check for name uniqueness if name is being updated
|
||||
if (data.name && settings.groups.some((g) => g.name === data.name && g.id !== id)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// If servers array is provided, validate server existence
|
||||
if (data.servers) {
|
||||
data.servers = data.servers.filter((serverName) => settings.mcpServers[serverName]);
|
||||
}
|
||||
|
||||
const updatedGroup = {
|
||||
...settings.groups[groupIndex],
|
||||
...data,
|
||||
};
|
||||
|
||||
settings.groups[groupIndex] = updatedGroup;
|
||||
|
||||
if (!saveSettings(settings)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
notifyToolChanged();
|
||||
return updatedGroup;
|
||||
} catch (error) {
|
||||
console.error(`Failed to update group ${id}:`, error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Update servers in a group (batch update)
|
||||
export const updateGroupServers = (groupId: string, servers: string[]): IGroup | null => {
|
||||
try {
|
||||
const settings = loadSettings();
|
||||
if (!settings.groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const groupIndex = settings.groups.findIndex((group) => group.id === groupId);
|
||||
if (groupIndex === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Filter out non-existent servers
|
||||
const validServers = servers.filter((serverName) => settings.mcpServers[serverName]);
|
||||
|
||||
settings.groups[groupIndex].servers = validServers;
|
||||
|
||||
if (!saveSettings(settings)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
notifyToolChanged();
|
||||
return settings.groups[groupIndex];
|
||||
} catch (error) {
|
||||
console.error(`Failed to update servers for group ${groupId}:`, error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Delete a group
|
||||
export const deleteGroup = (id: string): boolean => {
|
||||
try {
|
||||
const settings = loadSettings();
|
||||
if (!settings.groups) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const initialLength = settings.groups.length;
|
||||
settings.groups = settings.groups.filter((group) => group.id !== id);
|
||||
|
||||
if (settings.groups.length === initialLength) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return saveSettings(settings);
|
||||
} catch (error) {
|
||||
console.error(`Failed to delete group ${id}:`, error);
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Add server to group
|
||||
export const addServerToGroup = (groupId: string, serverName: string): IGroup | null => {
|
||||
try {
|
||||
const settings = loadSettings();
|
||||
if (!settings.groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Verify server exists
|
||||
if (!settings.mcpServers[serverName]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const groupIndex = settings.groups.findIndex((group) => group.id === groupId);
|
||||
if (groupIndex === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const group = settings.groups[groupIndex];
|
||||
|
||||
// Add server to group if not already in it
|
||||
if (!group.servers.includes(serverName)) {
|
||||
group.servers.push(serverName);
|
||||
|
||||
if (!saveSettings(settings)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
notifyToolChanged();
|
||||
return group;
|
||||
} catch (error) {
|
||||
console.error(`Failed to add server ${serverName} to group ${groupId}:`, error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Remove server from group
|
||||
export const removeServerFromGroup = (groupId: string, serverName: string): IGroup | null => {
|
||||
try {
|
||||
const settings = loadSettings();
|
||||
if (!settings.groups) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const groupIndex = settings.groups.findIndex((group) => group.id === groupId);
|
||||
if (groupIndex === -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const group = settings.groups[groupIndex];
|
||||
group.servers = group.servers.filter((name) => name !== serverName);
|
||||
|
||||
if (!saveSettings(settings)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return group;
|
||||
} catch (error) {
|
||||
console.error(`Failed to remove server ${serverName} from group ${groupId}:`, error);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
// Get all servers in a group
|
||||
export const getServersInGroup = (groupId: string): string[] => {
|
||||
const group = getGroupById(groupId);
|
||||
return group ? group.servers : [];
|
||||
};
|
||||
@@ -1,37 +1,34 @@
|
||||
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
||||
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
||||
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
||||
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
||||
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
||||
import * as z from 'zod';
|
||||
import { ZodType, ZodRawShape } from 'zod';
|
||||
import { ServerInfo, ServerConfig } from '../types/index.js';
|
||||
import { loadSettings, saveSettings, expandEnvVars } from '../config/index.js';
|
||||
import config from '../config/index.js';
|
||||
import { get } from 'http';
|
||||
import { getGroupId } from './sseService.js';
|
||||
import { getServersInGroup } from './groupService.js';
|
||||
|
||||
let mcpServer: McpServer;
|
||||
let currentServer: Server;
|
||||
|
||||
export const initMcpServer = (name: string, version: string): McpServer => {
|
||||
mcpServer = new McpServer({ name, version });
|
||||
return mcpServer;
|
||||
export const initMcpServer = async (name: string, version: string): Promise<void> => {
|
||||
currentServer = createMcpServer(name, version);
|
||||
await registerAllTools(currentServer, true);
|
||||
};
|
||||
|
||||
export const setMcpServer = (server: McpServer): void => {
|
||||
mcpServer = server;
|
||||
export const setMcpServer = (server: Server): void => {
|
||||
currentServer = server;
|
||||
};
|
||||
|
||||
export const getMcpServer = (): McpServer => {
|
||||
return mcpServer;
|
||||
export const getMcpServer = (): Server => {
|
||||
return currentServer;
|
||||
};
|
||||
|
||||
export const recreateMcpServer = async () => {
|
||||
console.log('Re-creating McpServer instance');
|
||||
const newServer = createMcpServer(config.mcpHubName, config.mcpHubVersion);
|
||||
await registerAllTools(newServer, true);
|
||||
const oldServer = getMcpServer();
|
||||
setMcpServer(newServer);
|
||||
oldServer.close();
|
||||
console.log('McpServer instance successfully re-created');
|
||||
export const notifyToolChanged = async () => {
|
||||
await registerAllTools(currentServer, true);
|
||||
currentServer.sendToolListChanged();
|
||||
console.log('Tool list changed notification sent');
|
||||
};
|
||||
|
||||
// Store all server information
|
||||
@@ -52,11 +49,11 @@ export const initializeClientsFromSettings = (): ServerInfo[] => {
|
||||
status: 'disconnected',
|
||||
tools: [],
|
||||
createTime: Date.now(),
|
||||
enabled: false
|
||||
enabled: false,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// Check if server is already connected
|
||||
const existingServer = existingServerInfos.find(
|
||||
(s) => s.name === name && s.status === 'connected',
|
||||
@@ -64,7 +61,7 @@ export const initializeClientsFromSettings = (): ServerInfo[] => {
|
||||
if (existingServer) {
|
||||
serverInfos.push({
|
||||
...existingServer,
|
||||
enabled: conf.enabled === undefined ? true : conf.enabled
|
||||
enabled: conf.enabled === undefined ? true : conf.enabled,
|
||||
});
|
||||
console.log(`Server '${name}' is already connected.`);
|
||||
continue;
|
||||
@@ -107,7 +104,7 @@ export const initializeClientsFromSettings = (): ServerInfo[] => {
|
||||
);
|
||||
client.connect(transport, { timeout: Number(config.timeout) }).catch((error) => {
|
||||
console.error(`Failed to connect client for server ${name} by error: ${error}`);
|
||||
const serverInfo = getServerInfoByName(name);
|
||||
const serverInfo = getServerByName(name);
|
||||
if (serverInfo) {
|
||||
serverInfo.status = 'disconnected';
|
||||
}
|
||||
@@ -127,7 +124,7 @@ export const initializeClientsFromSettings = (): ServerInfo[] => {
|
||||
};
|
||||
|
||||
// Register all MCP tools
|
||||
export const registerAllTools = async (server: McpServer, forceInit: boolean): Promise<void> => {
|
||||
export const registerAllTools = async (server: Server, forceInit: boolean): Promise<void> => {
|
||||
initializeClientsFromSettings();
|
||||
for (const serverInfo of serverInfos) {
|
||||
if (serverInfo.status === 'connected' && !forceInit) continue;
|
||||
@@ -136,35 +133,15 @@ export const registerAllTools = async (server: McpServer, forceInit: boolean): P
|
||||
try {
|
||||
serverInfo.status = 'connecting';
|
||||
console.log(`Connecting to server: ${serverInfo.name}...`);
|
||||
|
||||
const tools = await serverInfo.client.listTools({}, { timeout: Number(config.timeout) });
|
||||
serverInfo.tools = tools.tools.map((tool) => ({
|
||||
name: tool.name,
|
||||
description: tool.description || '',
|
||||
inputSchema: tool.inputSchema.properties || {},
|
||||
inputSchema: tool.inputSchema || {},
|
||||
}));
|
||||
|
||||
serverInfo.status = 'connected';
|
||||
console.log(`Successfully connected to server: ${serverInfo.name}`);
|
||||
|
||||
for (const tool of tools.tools) {
|
||||
console.log(`Registering tool: ${JSON.stringify(tool)}`);
|
||||
await server.tool(
|
||||
tool.name,
|
||||
tool.description || '',
|
||||
json2zod(tool.inputSchema.properties, tool.inputSchema.required),
|
||||
async (params: Record<string, unknown>) => {
|
||||
const currentServer = getServerInfoByName(serverInfo.name)!;
|
||||
console.log(`Calling tool: ${tool.name} with params: ${JSON.stringify(params)}`);
|
||||
const result = await currentServer.client!.callTool({
|
||||
name: tool.name,
|
||||
arguments: params,
|
||||
});
|
||||
console.log(`Tool call result: ${JSON.stringify(result)}`);
|
||||
return result as CallToolResult;
|
||||
},
|
||||
);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(
|
||||
`Failed to connect to server for client: ${serverInfo.name} by error: ${error}`,
|
||||
@@ -179,7 +156,7 @@ export const getServersInfo = (): Omit<ServerInfo, 'client' | 'transport'>[] =>
|
||||
const settings = loadSettings();
|
||||
const infos = serverInfos.map(({ name, status, tools, createTime }) => {
|
||||
const serverConfig = settings.mcpServers[name];
|
||||
const enabled = serverConfig ? (serverConfig.enabled !== false) : true;
|
||||
const enabled = serverConfig ? serverConfig.enabled !== false : true;
|
||||
return {
|
||||
name,
|
||||
status,
|
||||
@@ -195,11 +172,16 @@ export const getServersInfo = (): Omit<ServerInfo, 'client' | 'transport'>[] =>
|
||||
return infos;
|
||||
};
|
||||
|
||||
// Get server information by name
|
||||
const getServerInfoByName = (name: string): ServerInfo | undefined => {
|
||||
// Get server by name
|
||||
const getServerByName = (name: string): ServerInfo | undefined => {
|
||||
return serverInfos.find((serverInfo) => serverInfo.name === name);
|
||||
};
|
||||
|
||||
// Get server by tool name
|
||||
const getServerByTool = (toolName: string): ServerInfo | undefined => {
|
||||
return serverInfos.find((serverInfo) => serverInfo.tools.some((tool) => tool.name === toolName));
|
||||
};
|
||||
|
||||
// Add new server
|
||||
export const addServer = async (
|
||||
name: string,
|
||||
@@ -216,7 +198,7 @@ export const addServer = async (
|
||||
return { success: false, message: 'Failed to save settings' };
|
||||
}
|
||||
|
||||
registerAllTools(mcpServer, false);
|
||||
registerAllTools(currentServer, false);
|
||||
return { success: true, message: 'Server added successfully' };
|
||||
} catch (error) {
|
||||
console.error(`Failed to add server: ${name}`, error);
|
||||
@@ -228,7 +210,6 @@ export const addServer = async (
|
||||
export const removeServer = (name: string): { success: boolean; message?: string } => {
|
||||
try {
|
||||
const settings = loadSettings();
|
||||
|
||||
if (!settings.mcpServers[name]) {
|
||||
return { success: false, message: 'Server not found' };
|
||||
}
|
||||
@@ -263,13 +244,7 @@ export const updateMcpServer = async (
|
||||
return { success: false, message: 'Failed to save settings' };
|
||||
}
|
||||
|
||||
const serverInfo = serverInfos.find((serverInfo) => serverInfo.name === name);
|
||||
if (serverInfo) {
|
||||
serverInfo.client!.close();
|
||||
serverInfo.transport!.close();
|
||||
console.log(`Closed client and transport for server: ${name}`);
|
||||
// TODO kill process
|
||||
}
|
||||
closeServer(name);
|
||||
|
||||
serverInfos = serverInfos.filter((serverInfo) => serverInfo.name !== name);
|
||||
return { success: true, message: 'Server updated successfully' };
|
||||
@@ -279,10 +254,21 @@ export const updateMcpServer = async (
|
||||
}
|
||||
};
|
||||
|
||||
// Close server client and transport
|
||||
function closeServer(name: string) {
|
||||
const serverInfo = serverInfos.find((serverInfo) => serverInfo.name === name);
|
||||
if (serverInfo && serverInfo.client && serverInfo.transport) {
|
||||
serverInfo.client.close();
|
||||
serverInfo.transport.close();
|
||||
console.log(`Closed client and transport for server: ${serverInfo.name}`);
|
||||
// TODO kill process
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle server enabled status
|
||||
export const toggleServerStatus = async (
|
||||
name: string,
|
||||
enabled: boolean
|
||||
enabled: boolean,
|
||||
): Promise<{ success: boolean; message?: string }> => {
|
||||
try {
|
||||
const settings = loadSettings();
|
||||
@@ -292,22 +278,17 @@ export const toggleServerStatus = async (
|
||||
|
||||
// Update the enabled status in settings
|
||||
settings.mcpServers[name].enabled = enabled;
|
||||
|
||||
|
||||
if (!saveSettings(settings)) {
|
||||
return { success: false, message: 'Failed to save settings' };
|
||||
}
|
||||
|
||||
// If disabling, disconnect the server and remove from active servers
|
||||
if (!enabled) {
|
||||
const serverInfo = serverInfos.find((serverInfo) => serverInfo.name === name);
|
||||
if (serverInfo && serverInfo.client && serverInfo.transport) {
|
||||
serverInfo.client.close();
|
||||
serverInfo.transport.close();
|
||||
console.log(`Closed client and transport for server: ${name}`);
|
||||
}
|
||||
|
||||
closeServer(name);
|
||||
|
||||
// Update the server info to show as disconnected and disabled
|
||||
const index = serverInfos.findIndex(s => s.name === name);
|
||||
const index = serverInfos.findIndex((s) => s.name === name);
|
||||
if (index !== -1) {
|
||||
serverInfos[index] = {
|
||||
...serverInfos[index],
|
||||
@@ -325,92 +306,52 @@ export const toggleServerStatus = async (
|
||||
};
|
||||
|
||||
// Create McpServer instance
|
||||
export const createMcpServer = (name: string, version: string): McpServer => {
|
||||
return new McpServer({ name, version });
|
||||
export const createMcpServer = (name: string, version: string): Server => {
|
||||
const server = new Server({ name, version }, { capabilities: { tools: {} } });
|
||||
server.setRequestHandler(ListToolsRequestSchema, async (_, extra) => {
|
||||
const sessionId = extra.sessionId || '';
|
||||
const groupId = getGroupId(sessionId);
|
||||
console.log(`Handling ListToolsRequest for groupId: ${groupId}`);
|
||||
const allServerInfos = serverInfos.filter((serverInfo) => {
|
||||
if (serverInfo.enabled === false) return false;
|
||||
if (!groupId) return true;
|
||||
const serversInGroup = getServersInGroup(groupId);
|
||||
return serversInGroup.includes(serverInfo.name);
|
||||
});
|
||||
|
||||
const allTools = [];
|
||||
for (const serverInfo of allServerInfos) {
|
||||
if (serverInfo.tools && serverInfo.tools.length > 0) {
|
||||
allTools.push(...serverInfo.tools);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
tools: allTools,
|
||||
};
|
||||
});
|
||||
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request, _) => {
|
||||
console.log(`Handling CallToolRequest for tool: ${request.params.name}`);
|
||||
try {
|
||||
if (!request.params.arguments) {
|
||||
throw new Error('Arguments are required');
|
||||
}
|
||||
const serverInfo = getServerByTool(request.params.name);
|
||||
if (!serverInfo) {
|
||||
throw new Error(`Server not found: ${request.params.name}`);
|
||||
}
|
||||
const client = serverInfo.client;
|
||||
if (!client) {
|
||||
throw new Error(`Client not found for server: ${request.params.name}`);
|
||||
}
|
||||
const result = await client.callTool(request.params);
|
||||
console.log(`Tool call result: ${JSON.stringify(result)}`);
|
||||
return result;
|
||||
} catch (error) {
|
||||
console.error(`Error handling CallToolRequest: ${error}`);
|
||||
return { error: `Failed to call tool: ${error}` };
|
||||
}
|
||||
});
|
||||
return server;
|
||||
};
|
||||
|
||||
// Helper function: Convert JSON Schema to Zod Schema
|
||||
function json2zod(inputSchema: unknown, required: unknown): ZodRawShape {
|
||||
if (typeof inputSchema !== 'object' || inputSchema === null) {
|
||||
throw new Error('Invalid input schema');
|
||||
}
|
||||
|
||||
const properties = inputSchema as Record<string, any>;
|
||||
const processedSchema: ZodRawShape = {};
|
||||
|
||||
for (const key in properties) {
|
||||
const prop = properties[key];
|
||||
|
||||
if (prop instanceof ZodType) {
|
||||
processedSchema[key] = prop;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (typeof prop !== 'object' || prop === null) {
|
||||
throw new Error(`Invalid property definition for ${key}`);
|
||||
}
|
||||
|
||||
let zodType: ZodType;
|
||||
|
||||
if (prop.type === 'array' && prop.items) {
|
||||
if (prop.items.type === 'string') {
|
||||
zodType = z.array(z.string());
|
||||
} else if (prop.items.type === 'number') {
|
||||
zodType = z.array(z.number());
|
||||
} else if (prop.items.type === 'integer') {
|
||||
zodType = z.array(z.number().int());
|
||||
} else if (prop.items.type === 'boolean') {
|
||||
zodType = z.array(z.boolean());
|
||||
} else if (prop.items.type === 'object' && prop.items.properties) {
|
||||
zodType = z.array(z.object(json2zod(prop.items.properties, prop.items.required)));
|
||||
} else {
|
||||
zodType = z.array(z.any());
|
||||
}
|
||||
} else {
|
||||
switch (prop.type) {
|
||||
case 'string':
|
||||
if (prop.enum && Array.isArray(prop.enum)) {
|
||||
zodType = z.enum(prop.enum as [string, ...string[]]);
|
||||
} else {
|
||||
zodType = z.string();
|
||||
}
|
||||
break;
|
||||
case 'number':
|
||||
zodType = z.number();
|
||||
break;
|
||||
case 'boolean':
|
||||
zodType = z.boolean();
|
||||
break;
|
||||
case 'integer':
|
||||
zodType = z.number().int();
|
||||
break;
|
||||
case 'object':
|
||||
if (prop.properties) {
|
||||
zodType = z.object(json2zod(prop.properties, prop.required));
|
||||
} else {
|
||||
zodType = z.record(z.any());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
zodType = z.any();
|
||||
}
|
||||
}
|
||||
|
||||
if (prop.description) {
|
||||
zodType = zodType.describe(prop.description);
|
||||
}
|
||||
|
||||
if (prop.default !== undefined) {
|
||||
zodType = zodType.default(prop.default);
|
||||
}
|
||||
|
||||
required = Array.isArray(required) ? required : [];
|
||||
if (Array.isArray(required) && required.includes(key)) {
|
||||
processedSchema[key] = zodType;
|
||||
} else {
|
||||
processedSchema[key] = zodType.optional();
|
||||
}
|
||||
}
|
||||
|
||||
return processedSchema;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,16 @@ import { Request, Response } from 'express';
|
||||
import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js';
|
||||
import { getMcpServer } from './mcpService.js';
|
||||
|
||||
const transports: { [sessionId: string]: SSEServerTransport } = {};
|
||||
const transports: { [sessionId: string]: { transport: SSEServerTransport; groupId: string } } = {};
|
||||
|
||||
export const getGroupId = (sessionId: string): string => {
|
||||
return transports[sessionId]?.groupId || '';
|
||||
};
|
||||
|
||||
export const handleSseConnection = async (req: Request, res: Response): Promise<void> => {
|
||||
const transport = new SSEServerTransport('/messages', res);
|
||||
transports[transport.sessionId] = transport;
|
||||
const groupId = req.params.groupId;
|
||||
transports[transport.sessionId] = { transport, groupId };
|
||||
|
||||
res.on('close', () => {
|
||||
delete transports[transport.sessionId];
|
||||
@@ -19,8 +24,10 @@ export const handleSseConnection = async (req: Request, res: Response): Promise<
|
||||
|
||||
export const handleSseMessage = async (req: Request, res: Response): Promise<void> => {
|
||||
const sessionId = req.query.sessionId as string;
|
||||
const transport = transports[sessionId];
|
||||
|
||||
const { transport, groupId } = transports[sessionId];
|
||||
req.params.groupId = groupId;
|
||||
req.query.groupId = groupId;
|
||||
console.log(`Received message for sessionId: ${sessionId} in groupId: ${groupId}`);
|
||||
if (transport) {
|
||||
await transport.handlePostMessage(req, res);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user