191 lines
5.1 KiB
TypeScript
191 lines
5.1 KiB
TypeScript
|
|
import { writable, get } from 'svelte/store';
|
||
|
|
import { MudConnection } from './MudConnection';
|
||
|
|
import type { GmcpHandler } from '$lib/gmcp/GmcpHandler';
|
||
|
|
import { connectionStatus } from '$lib/stores/mudStore';
|
||
|
|
|
||
|
|
// Store for active MUD connections (persistent across tab switches)
|
||
|
|
export const activeConnections = writable<{ [key: string]: MudConnection }>({});
|
||
|
|
|
||
|
|
/**
|
||
|
|
* ConnectionManager - Singleton service to manage MUD connections
|
||
|
|
* This ensures connections stay alive even when components are unmounted during tab switches
|
||
|
|
*/
|
||
|
|
export class ConnectionManager {
|
||
|
|
private static instance: ConnectionManager;
|
||
|
|
|
||
|
|
// Private constructor for singleton pattern
|
||
|
|
private constructor() {
|
||
|
|
console.log('ConnectionManager initialized');
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get the singleton instance of ConnectionManager
|
||
|
|
*/
|
||
|
|
public static getInstance(): ConnectionManager {
|
||
|
|
if (!ConnectionManager.instance) {
|
||
|
|
ConnectionManager.instance = new ConnectionManager();
|
||
|
|
}
|
||
|
|
return ConnectionManager.instance;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get an existing connection without creating a new one
|
||
|
|
*/
|
||
|
|
public getExistingConnection(profileId: string): MudConnection | null {
|
||
|
|
const connections = get(activeConnections);
|
||
|
|
return connections[profileId] || null;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create a new connection or return an existing one
|
||
|
|
*/
|
||
|
|
public getConnection(profileId: string, options: {
|
||
|
|
host: string;
|
||
|
|
port: number;
|
||
|
|
useSSL?: boolean;
|
||
|
|
gmcpHandler?: GmcpHandler;
|
||
|
|
}): MudConnection {
|
||
|
|
// Get current connections
|
||
|
|
const connections = get(activeConnections);
|
||
|
|
|
||
|
|
// Check if a connection already exists for this profile
|
||
|
|
if (connections[profileId]) {
|
||
|
|
console.log(`Returning existing connection for profile ${profileId}`);
|
||
|
|
return connections[profileId];
|
||
|
|
}
|
||
|
|
|
||
|
|
// Create a new connection
|
||
|
|
console.log(`Creating new connection for profile ${profileId}`);
|
||
|
|
const connection = new MudConnection({
|
||
|
|
host: options.host,
|
||
|
|
port: options.port,
|
||
|
|
useSSL: options.useSSL,
|
||
|
|
gmcpHandler: options.gmcpHandler
|
||
|
|
});
|
||
|
|
|
||
|
|
// Set up event handlers
|
||
|
|
this.setupConnectionEvents(connection, profileId);
|
||
|
|
|
||
|
|
// Store the connection
|
||
|
|
activeConnections.update(connections => ({
|
||
|
|
...connections,
|
||
|
|
[profileId]: connection
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Return the connection
|
||
|
|
return connection;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Connect to a MUD server
|
||
|
|
*/
|
||
|
|
public connect(profileId: string, options: {
|
||
|
|
host: string;
|
||
|
|
port: number;
|
||
|
|
useSSL?: boolean;
|
||
|
|
gmcpHandler?: GmcpHandler;
|
||
|
|
}): void {
|
||
|
|
const connection = this.getConnection(profileId, options);
|
||
|
|
|
||
|
|
// Update connection status
|
||
|
|
connectionStatus.update(statuses => ({
|
||
|
|
...statuses,
|
||
|
|
[profileId]: 'connecting'
|
||
|
|
}));
|
||
|
|
|
||
|
|
// Connect
|
||
|
|
connection.connect();
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Disconnect from a MUD server
|
||
|
|
*/
|
||
|
|
public disconnect(profileId: string): void {
|
||
|
|
const connections = get(activeConnections);
|
||
|
|
|
||
|
|
if (connections[profileId]) {
|
||
|
|
connections[profileId].disconnect();
|
||
|
|
|
||
|
|
// Update connection status
|
||
|
|
connectionStatus.update(statuses => ({
|
||
|
|
...statuses,
|
||
|
|
[profileId]: 'disconnected'
|
||
|
|
}));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Send text to a MUD server
|
||
|
|
*/
|
||
|
|
public send(profileId: string, text: string): void {
|
||
|
|
const connections = get(activeConnections);
|
||
|
|
|
||
|
|
if (connections[profileId]) {
|
||
|
|
connections[profileId].send(text);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Close a connection and remove it
|
||
|
|
*/
|
||
|
|
public closeConnection(profileId: string): void {
|
||
|
|
const connections = get(activeConnections);
|
||
|
|
|
||
|
|
if (connections[profileId]) {
|
||
|
|
// Disconnect first
|
||
|
|
connections[profileId].disconnect();
|
||
|
|
|
||
|
|
// Then remove from store
|
||
|
|
activeConnections.update(connections => {
|
||
|
|
const newConnections = { ...connections };
|
||
|
|
delete newConnections[profileId];
|
||
|
|
return newConnections;
|
||
|
|
});
|
||
|
|
|
||
|
|
// Update connection status
|
||
|
|
connectionStatus.update(statuses => {
|
||
|
|
const newStatuses = { ...statuses };
|
||
|
|
delete newStatuses[profileId];
|
||
|
|
return newStatuses;
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Set up event handlers for a connection
|
||
|
|
*/
|
||
|
|
private setupConnectionEvents(connection: MudConnection, profileId: string): void {
|
||
|
|
// Handle connection established
|
||
|
|
connection.on('connected', () => {
|
||
|
|
console.log(`ConnectionManager: Connection established for profile ${profileId}`);
|
||
|
|
|
||
|
|
// Update connection status
|
||
|
|
connectionStatus.update(statuses => ({
|
||
|
|
...statuses,
|
||
|
|
[profileId]: 'connected'
|
||
|
|
}));
|
||
|
|
});
|
||
|
|
|
||
|
|
// Handle connection closed
|
||
|
|
connection.on('disconnected', () => {
|
||
|
|
console.log(`ConnectionManager: Connection closed for profile ${profileId}`);
|
||
|
|
|
||
|
|
// Update connection status
|
||
|
|
connectionStatus.update(statuses => ({
|
||
|
|
...statuses,
|
||
|
|
[profileId]: 'disconnected'
|
||
|
|
}));
|
||
|
|
});
|
||
|
|
|
||
|
|
// Handle connection error
|
||
|
|
connection.on('error', (error) => {
|
||
|
|
console.error(`ConnectionManager: Connection error for profile ${profileId}:`, error);
|
||
|
|
|
||
|
|
// Update connection status
|
||
|
|
connectionStatus.update(statuses => ({
|
||
|
|
...statuses,
|
||
|
|
[profileId]: 'error'
|
||
|
|
}));
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|