lit-shell.js 0.1.4 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/dist/client/browser-bundle.js +240 -4
- package/dist/client/browser-bundle.js.map +2 -2
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/terminal-client.d.ts +78 -3
- package/dist/client/terminal-client.d.ts.map +1 -1
- package/dist/client/terminal-client.js +237 -4
- package/dist/client/terminal-client.js.map +1 -1
- package/dist/server/circular-buffer.d.ts +55 -0
- package/dist/server/circular-buffer.d.ts.map +1 -0
- package/dist/server/circular-buffer.js +91 -0
- package/dist/server/circular-buffer.js.map +1 -0
- package/dist/server/index.d.ts +4 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +3 -0
- package/dist/server/index.js.map +1 -1
- package/dist/server/session-manager.d.ts +195 -0
- package/dist/server/session-manager.d.ts.map +1 -0
- package/dist/server/session-manager.js +448 -0
- package/dist/server/session-manager.js.map +1 -0
- package/dist/server/terminal-server.d.ts +75 -5
- package/dist/server/terminal-server.d.ts.map +1 -1
- package/dist/server/terminal-server.js +496 -79
- package/dist/server/terminal-server.js.map +1 -1
- package/dist/shared/types.d.ts +179 -2
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/ui/browser-bundle.js +240 -4
- package/dist/ui/browser-bundle.js.map +3 -3
- package/package.json +9 -4
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session manager for multiplexed terminal sessions.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Manage shared session lifecycle
|
|
6
|
+
* - Track client connections per session
|
|
7
|
+
* - Handle orphan session cleanup
|
|
8
|
+
* - Maintain history buffers
|
|
9
|
+
* - Broadcast messages to session clients
|
|
10
|
+
*/
|
|
11
|
+
import { EventEmitter } from 'events';
|
|
12
|
+
import type { WebSocket } from 'ws';
|
|
13
|
+
import { CircularBuffer } from './circular-buffer.js';
|
|
14
|
+
import type { SessionType, SharedSessionInfo, SessionListFilter } from '../shared/types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Session manager configuration
|
|
17
|
+
*/
|
|
18
|
+
export interface SessionManagerConfig {
|
|
19
|
+
/** Maximum clients per session (default: 10) */
|
|
20
|
+
maxClientsPerSession?: number;
|
|
21
|
+
/** Orphan timeout in ms before killing session (default: 60000) */
|
|
22
|
+
orphanTimeout?: number;
|
|
23
|
+
/** History buffer size in characters (default: 50000) */
|
|
24
|
+
historySize?: number;
|
|
25
|
+
/** Enable history by default (default: true) */
|
|
26
|
+
historyEnabled?: boolean;
|
|
27
|
+
/** Maximum total sessions (default: 100) */
|
|
28
|
+
maxSessionsTotal?: number;
|
|
29
|
+
/** Verbose logging (default: false) */
|
|
30
|
+
verbose?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Client info for session management
|
|
34
|
+
*/
|
|
35
|
+
export interface ClientInfo {
|
|
36
|
+
id: string;
|
|
37
|
+
ws: WebSocket;
|
|
38
|
+
joinedAt: Date;
|
|
39
|
+
lastActivity: Date;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Shared terminal session supporting multiple clients
|
|
43
|
+
*/
|
|
44
|
+
export interface SharedSession {
|
|
45
|
+
id: string;
|
|
46
|
+
type: SessionType;
|
|
47
|
+
pty: any;
|
|
48
|
+
shell: string;
|
|
49
|
+
cwd: string;
|
|
50
|
+
cols: number;
|
|
51
|
+
rows: number;
|
|
52
|
+
createdAt: Date;
|
|
53
|
+
lastActivity: Date;
|
|
54
|
+
container?: string;
|
|
55
|
+
clients: Map<string, ClientInfo>;
|
|
56
|
+
owner: string;
|
|
57
|
+
label?: string;
|
|
58
|
+
accepting: boolean;
|
|
59
|
+
historyBuffer: CircularBuffer;
|
|
60
|
+
historyEnabled: boolean;
|
|
61
|
+
orphanedAt: Date | null;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Events emitted by SessionManager
|
|
65
|
+
*/
|
|
66
|
+
export interface SessionManagerEvents {
|
|
67
|
+
sessionCreated: (session: SharedSession) => void;
|
|
68
|
+
sessionClosed: (sessionId: string, reason: string) => void;
|
|
69
|
+
clientJoined: (sessionId: string, clientId: string, clientCount: number) => void;
|
|
70
|
+
clientLeft: (sessionId: string, clientId: string, clientCount: number) => void;
|
|
71
|
+
sessionOrphaned: (sessionId: string) => void;
|
|
72
|
+
error: (error: Error, context: string) => void;
|
|
73
|
+
}
|
|
74
|
+
export declare class SessionManager extends EventEmitter {
|
|
75
|
+
private sessions;
|
|
76
|
+
private clientToSessions;
|
|
77
|
+
private orphanTimers;
|
|
78
|
+
private config;
|
|
79
|
+
constructor(config?: SessionManagerConfig);
|
|
80
|
+
private log;
|
|
81
|
+
/**
|
|
82
|
+
* Create a new shared session.
|
|
83
|
+
*/
|
|
84
|
+
createSession(options: {
|
|
85
|
+
id: string;
|
|
86
|
+
type: SessionType;
|
|
87
|
+
pty: any;
|
|
88
|
+
shell: string;
|
|
89
|
+
cwd: string;
|
|
90
|
+
cols: number;
|
|
91
|
+
rows: number;
|
|
92
|
+
ownerId: string;
|
|
93
|
+
ownerWs: WebSocket;
|
|
94
|
+
container?: string;
|
|
95
|
+
label?: string;
|
|
96
|
+
allowJoin?: boolean;
|
|
97
|
+
enableHistory?: boolean;
|
|
98
|
+
}): SharedSession;
|
|
99
|
+
/**
|
|
100
|
+
* Get a session by ID.
|
|
101
|
+
*/
|
|
102
|
+
getSession(sessionId: string): SharedSession | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Get all sessions, optionally filtered.
|
|
105
|
+
*/
|
|
106
|
+
getSessions(filter?: SessionListFilter): SharedSession[];
|
|
107
|
+
/**
|
|
108
|
+
* Close a session and clean up.
|
|
109
|
+
*/
|
|
110
|
+
closeSession(sessionId: string, reason: string): void;
|
|
111
|
+
/**
|
|
112
|
+
* Check if a session exists.
|
|
113
|
+
*/
|
|
114
|
+
hasSession(sessionId: string): boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Get session count.
|
|
117
|
+
*/
|
|
118
|
+
getSessionCount(): number;
|
|
119
|
+
/**
|
|
120
|
+
* Add a client to a session.
|
|
121
|
+
*/
|
|
122
|
+
addClient(sessionId: string, clientId: string, ws: WebSocket): boolean;
|
|
123
|
+
/**
|
|
124
|
+
* Remove a client from a session.
|
|
125
|
+
*/
|
|
126
|
+
removeClient(sessionId: string, clientId: string): void;
|
|
127
|
+
/**
|
|
128
|
+
* Remove a client from all sessions.
|
|
129
|
+
*/
|
|
130
|
+
removeClientFromAllSessions(clientId: string): string[];
|
|
131
|
+
/**
|
|
132
|
+
* Get all clients in a session.
|
|
133
|
+
*/
|
|
134
|
+
getSessionClients(sessionId: string): ClientInfo[];
|
|
135
|
+
/**
|
|
136
|
+
* Get client count for a session.
|
|
137
|
+
*/
|
|
138
|
+
getClientCount(sessionId: string): number;
|
|
139
|
+
/**
|
|
140
|
+
* Check if a client is in a session.
|
|
141
|
+
*/
|
|
142
|
+
isClientInSession(sessionId: string, clientId: string): boolean;
|
|
143
|
+
/**
|
|
144
|
+
* Get all sessions a client is in.
|
|
145
|
+
*/
|
|
146
|
+
getClientSessions(clientId: string): string[];
|
|
147
|
+
private trackClientSession;
|
|
148
|
+
/**
|
|
149
|
+
* Broadcast a message to all clients in a session.
|
|
150
|
+
*/
|
|
151
|
+
broadcastToSession(sessionId: string, message: object, excludeClientId?: string): void;
|
|
152
|
+
/**
|
|
153
|
+
* Send a message to a specific client in a session.
|
|
154
|
+
*/
|
|
155
|
+
sendToClient(sessionId: string, clientId: string, message: object): boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Append data to a session's history buffer.
|
|
158
|
+
*/
|
|
159
|
+
appendHistory(sessionId: string, data: string): void;
|
|
160
|
+
/**
|
|
161
|
+
* Get history from a session.
|
|
162
|
+
*/
|
|
163
|
+
getHistory(sessionId: string, limit?: number): string;
|
|
164
|
+
/**
|
|
165
|
+
* Clear history for a session.
|
|
166
|
+
*/
|
|
167
|
+
clearHistory(sessionId: string): void;
|
|
168
|
+
/**
|
|
169
|
+
* Update last activity timestamp for a session.
|
|
170
|
+
*/
|
|
171
|
+
updateSessionActivity(sessionId: string): void;
|
|
172
|
+
/**
|
|
173
|
+
* Update last activity for a client.
|
|
174
|
+
*/
|
|
175
|
+
updateClientActivity(sessionId: string, clientId: string): void;
|
|
176
|
+
private handleOrphanedSession;
|
|
177
|
+
private clearOrphanTimer;
|
|
178
|
+
/**
|
|
179
|
+
* Convert a session to SharedSessionInfo for client consumption.
|
|
180
|
+
*/
|
|
181
|
+
toSharedSessionInfo(session: SharedSession): SharedSessionInfo;
|
|
182
|
+
/**
|
|
183
|
+
* Clean up all sessions and resources.
|
|
184
|
+
*/
|
|
185
|
+
cleanup(): void;
|
|
186
|
+
/**
|
|
187
|
+
* Get manager statistics.
|
|
188
|
+
*/
|
|
189
|
+
getStats(): {
|
|
190
|
+
sessionCount: number;
|
|
191
|
+
clientCount: number;
|
|
192
|
+
orphanedCount: number;
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=session-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.d.ts","sourceRoot":"","sources":["../../src/server/session-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,KAAK,EACV,WAAW,EACX,iBAAiB,EACjB,iBAAiB,EAElB,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,gDAAgD;IAChD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mEAAmE;IACnE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,uCAAuC;IACvC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,SAAS,CAAC;IACd,QAAQ,EAAE,IAAI,CAAC;IACf,YAAY,EAAE,IAAI,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,GAAG,EAAE,GAAG,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,IAAI,CAAC;IAChB,YAAY,EAAE,IAAI,CAAC;IAGnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IAGnB,aAAa,EAAE,cAAc,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IAGxB,UAAU,EAAE,IAAI,GAAG,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,cAAc,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,IAAI,CAAC;IACjD,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,YAAY,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACjF,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/E,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,KAAK,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAChD;AAED,qBAAa,cAAe,SAAQ,YAAY;IAC9C,OAAO,CAAC,QAAQ,CAAoC;IACpD,OAAO,CAAC,gBAAgB,CAAkC;IAC1D,OAAO,CAAC,YAAY,CAAqC;IACzD,OAAO,CAAC,MAAM,CAAiC;gBAEnC,MAAM,GAAE,oBAAyB;IAY7C,OAAO,CAAC,GAAG;IAiBX;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE;QACrB,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,WAAW,CAAC;QAClB,GAAG,EAAE,GAAG,CAAC;QACT,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,EAAE,SAAS,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,OAAO,CAAC;QACpB,aAAa,CAAC,EAAE,OAAO,CAAC;KACzB,GAAG,aAAa;IA6CjB;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIxD;;OAEG;IACH,WAAW,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,aAAa,EAAE;IAkBxD;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAgCrD;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItC;;OAEG;IACH,eAAe,IAAI,MAAM;IAQzB;;OAEG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,GAAG,OAAO;IAwCtE;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IA0BvD;;OAEG;IACH,2BAA2B,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAYvD;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE;IAKlD;;OAEG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAKzC;;OAEG;IACH,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO;IAK/D;;OAEG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;IAK7C,OAAO,CAAC,kBAAkB;IAa1B;;OAEG;IACH,kBAAkB,CAChB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,eAAe,CAAC,EAAE,MAAM,GACvB,IAAI;IAoBP;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO;IAuB3E;;OAEG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAOpD;;OAEG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM;IAMrD;;OAEG;IACH,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAWrC;;OAEG;IACH,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAO9C;;OAEG;IACH,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAe/D,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,gBAAgB;IAYxB;;OAEG;IACH,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,iBAAiB;IAsB9D;;OAEG;IACH,OAAO,IAAI,IAAI;IAiBf;;OAEG;IACH,QAAQ,IAAI;QACV,YAAY,EAAE,MAAM,CAAC;QACrB,WAAW,EAAE,MAAM,CAAC;QACpB,aAAa,EAAE,MAAM,CAAC;KACvB;CAYF"}
|
|
@@ -0,0 +1,448 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session manager for multiplexed terminal sessions.
|
|
3
|
+
*
|
|
4
|
+
* Responsibilities:
|
|
5
|
+
* - Manage shared session lifecycle
|
|
6
|
+
* - Track client connections per session
|
|
7
|
+
* - Handle orphan session cleanup
|
|
8
|
+
* - Maintain history buffers
|
|
9
|
+
* - Broadcast messages to session clients
|
|
10
|
+
*/
|
|
11
|
+
import { EventEmitter } from 'events';
|
|
12
|
+
import { CircularBuffer } from './circular-buffer.js';
|
|
13
|
+
export class SessionManager extends EventEmitter {
|
|
14
|
+
constructor(config = {}) {
|
|
15
|
+
super();
|
|
16
|
+
this.sessions = new Map();
|
|
17
|
+
this.clientToSessions = new Map(); // clientId -> sessionIds
|
|
18
|
+
this.orphanTimers = new Map();
|
|
19
|
+
this.config = {
|
|
20
|
+
maxClientsPerSession: config.maxClientsPerSession ?? 10,
|
|
21
|
+
orphanTimeout: config.orphanTimeout ?? 60000,
|
|
22
|
+
historySize: config.historySize ?? 50000,
|
|
23
|
+
historyEnabled: config.historyEnabled ?? true,
|
|
24
|
+
maxSessionsTotal: config.maxSessionsTotal ?? 100,
|
|
25
|
+
verbose: config.verbose ?? false,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
log(message, level = 'info') {
|
|
29
|
+
if (this.config.verbose || level === 'error') {
|
|
30
|
+
const prefix = `[SessionManager]`;
|
|
31
|
+
if (level === 'error') {
|
|
32
|
+
console.error(`${prefix} ${message}`);
|
|
33
|
+
}
|
|
34
|
+
else if (level === 'warn') {
|
|
35
|
+
console.warn(`${prefix} ${message}`);
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.log(`${prefix} ${message}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// ==========================================================================
|
|
43
|
+
// Session CRUD
|
|
44
|
+
// ==========================================================================
|
|
45
|
+
/**
|
|
46
|
+
* Create a new shared session.
|
|
47
|
+
*/
|
|
48
|
+
createSession(options) {
|
|
49
|
+
if (this.sessions.size >= this.config.maxSessionsTotal) {
|
|
50
|
+
throw new Error('Maximum number of sessions reached');
|
|
51
|
+
}
|
|
52
|
+
const now = new Date();
|
|
53
|
+
const session = {
|
|
54
|
+
id: options.id,
|
|
55
|
+
type: options.type,
|
|
56
|
+
pty: options.pty,
|
|
57
|
+
shell: options.shell,
|
|
58
|
+
cwd: options.cwd,
|
|
59
|
+
cols: options.cols,
|
|
60
|
+
rows: options.rows,
|
|
61
|
+
createdAt: now,
|
|
62
|
+
lastActivity: now,
|
|
63
|
+
container: options.container,
|
|
64
|
+
clients: new Map(),
|
|
65
|
+
owner: options.ownerId,
|
|
66
|
+
label: options.label,
|
|
67
|
+
accepting: options.allowJoin !== false,
|
|
68
|
+
historyBuffer: new CircularBuffer(this.config.historySize),
|
|
69
|
+
historyEnabled: options.enableHistory !== false && this.config.historyEnabled,
|
|
70
|
+
orphanedAt: null,
|
|
71
|
+
};
|
|
72
|
+
// Add owner as first client
|
|
73
|
+
session.clients.set(options.ownerId, {
|
|
74
|
+
id: options.ownerId,
|
|
75
|
+
ws: options.ownerWs,
|
|
76
|
+
joinedAt: now,
|
|
77
|
+
lastActivity: now,
|
|
78
|
+
});
|
|
79
|
+
// Track client -> sessions mapping
|
|
80
|
+
this.trackClientSession(options.ownerId, session.id);
|
|
81
|
+
this.sessions.set(session.id, session);
|
|
82
|
+
this.log(`Created session ${session.id} (type: ${session.type}, owner: ${options.ownerId})`);
|
|
83
|
+
this.emit('sessionCreated', session);
|
|
84
|
+
return session;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get a session by ID.
|
|
88
|
+
*/
|
|
89
|
+
getSession(sessionId) {
|
|
90
|
+
return this.sessions.get(sessionId);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get all sessions, optionally filtered.
|
|
94
|
+
*/
|
|
95
|
+
getSessions(filter) {
|
|
96
|
+
let sessions = Array.from(this.sessions.values());
|
|
97
|
+
if (filter) {
|
|
98
|
+
if (filter.type) {
|
|
99
|
+
sessions = sessions.filter((s) => s.type === filter.type);
|
|
100
|
+
}
|
|
101
|
+
if (filter.container) {
|
|
102
|
+
sessions = sessions.filter((s) => s.container === filter.container);
|
|
103
|
+
}
|
|
104
|
+
if (filter.accepting !== undefined) {
|
|
105
|
+
sessions = sessions.filter((s) => s.accepting === filter.accepting);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return sessions;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Close a session and clean up.
|
|
112
|
+
*/
|
|
113
|
+
closeSession(sessionId, reason) {
|
|
114
|
+
const session = this.sessions.get(sessionId);
|
|
115
|
+
if (!session)
|
|
116
|
+
return;
|
|
117
|
+
this.log(`Closing session ${sessionId} (reason: ${reason})`);
|
|
118
|
+
// Clear orphan timer if any
|
|
119
|
+
this.clearOrphanTimer(sessionId);
|
|
120
|
+
// Kill PTY
|
|
121
|
+
try {
|
|
122
|
+
session.pty.kill();
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
this.log(`Error killing PTY for session ${sessionId}: ${e}`, 'warn');
|
|
126
|
+
}
|
|
127
|
+
// Remove session from all client mappings
|
|
128
|
+
for (const clientId of session.clients.keys()) {
|
|
129
|
+
const clientSessions = this.clientToSessions.get(clientId);
|
|
130
|
+
if (clientSessions) {
|
|
131
|
+
clientSessions.delete(sessionId);
|
|
132
|
+
if (clientSessions.size === 0) {
|
|
133
|
+
this.clientToSessions.delete(clientId);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Remove session
|
|
138
|
+
this.sessions.delete(sessionId);
|
|
139
|
+
this.emit('sessionClosed', sessionId, reason);
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Check if a session exists.
|
|
143
|
+
*/
|
|
144
|
+
hasSession(sessionId) {
|
|
145
|
+
return this.sessions.has(sessionId);
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get session count.
|
|
149
|
+
*/
|
|
150
|
+
getSessionCount() {
|
|
151
|
+
return this.sessions.size;
|
|
152
|
+
}
|
|
153
|
+
// ==========================================================================
|
|
154
|
+
// Client Management
|
|
155
|
+
// ==========================================================================
|
|
156
|
+
/**
|
|
157
|
+
* Add a client to a session.
|
|
158
|
+
*/
|
|
159
|
+
addClient(sessionId, clientId, ws) {
|
|
160
|
+
const session = this.sessions.get(sessionId);
|
|
161
|
+
if (!session) {
|
|
162
|
+
this.log(`Cannot add client to non-existent session ${sessionId}`, 'warn');
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
if (!session.accepting) {
|
|
166
|
+
this.log(`Session ${sessionId} is not accepting new clients`, 'warn');
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
if (session.clients.size >= this.config.maxClientsPerSession) {
|
|
170
|
+
this.log(`Session ${sessionId} is full`, 'warn');
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
// If session was orphaned, clear the timer
|
|
174
|
+
if (session.orphanedAt) {
|
|
175
|
+
session.orphanedAt = null;
|
|
176
|
+
this.clearOrphanTimer(sessionId);
|
|
177
|
+
this.log(`Session ${sessionId} is no longer orphaned`);
|
|
178
|
+
}
|
|
179
|
+
const now = new Date();
|
|
180
|
+
session.clients.set(clientId, {
|
|
181
|
+
id: clientId,
|
|
182
|
+
ws,
|
|
183
|
+
joinedAt: now,
|
|
184
|
+
lastActivity: now,
|
|
185
|
+
});
|
|
186
|
+
this.trackClientSession(clientId, sessionId);
|
|
187
|
+
this.log(`Client ${clientId} joined session ${sessionId} (${session.clients.size} clients)`);
|
|
188
|
+
this.emit('clientJoined', sessionId, clientId, session.clients.size);
|
|
189
|
+
return true;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Remove a client from a session.
|
|
193
|
+
*/
|
|
194
|
+
removeClient(sessionId, clientId) {
|
|
195
|
+
const session = this.sessions.get(sessionId);
|
|
196
|
+
if (!session)
|
|
197
|
+
return;
|
|
198
|
+
if (!session.clients.has(clientId))
|
|
199
|
+
return;
|
|
200
|
+
session.clients.delete(clientId);
|
|
201
|
+
// Update client -> sessions mapping
|
|
202
|
+
const clientSessions = this.clientToSessions.get(clientId);
|
|
203
|
+
if (clientSessions) {
|
|
204
|
+
clientSessions.delete(sessionId);
|
|
205
|
+
if (clientSessions.size === 0) {
|
|
206
|
+
this.clientToSessions.delete(clientId);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
this.log(`Client ${clientId} left session ${sessionId} (${session.clients.size} clients remaining)`);
|
|
210
|
+
this.emit('clientLeft', sessionId, clientId, session.clients.size);
|
|
211
|
+
// Check if session is now orphaned
|
|
212
|
+
if (session.clients.size === 0) {
|
|
213
|
+
this.handleOrphanedSession(session);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Remove a client from all sessions.
|
|
218
|
+
*/
|
|
219
|
+
removeClientFromAllSessions(clientId) {
|
|
220
|
+
const clientSessions = this.clientToSessions.get(clientId);
|
|
221
|
+
if (!clientSessions)
|
|
222
|
+
return [];
|
|
223
|
+
const sessionIds = Array.from(clientSessions);
|
|
224
|
+
for (const sessionId of sessionIds) {
|
|
225
|
+
this.removeClient(sessionId, clientId);
|
|
226
|
+
}
|
|
227
|
+
return sessionIds;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Get all clients in a session.
|
|
231
|
+
*/
|
|
232
|
+
getSessionClients(sessionId) {
|
|
233
|
+
const session = this.sessions.get(sessionId);
|
|
234
|
+
return session ? Array.from(session.clients.values()) : [];
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Get client count for a session.
|
|
238
|
+
*/
|
|
239
|
+
getClientCount(sessionId) {
|
|
240
|
+
const session = this.sessions.get(sessionId);
|
|
241
|
+
return session ? session.clients.size : 0;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Check if a client is in a session.
|
|
245
|
+
*/
|
|
246
|
+
isClientInSession(sessionId, clientId) {
|
|
247
|
+
const session = this.sessions.get(sessionId);
|
|
248
|
+
return session ? session.clients.has(clientId) : false;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Get all sessions a client is in.
|
|
252
|
+
*/
|
|
253
|
+
getClientSessions(clientId) {
|
|
254
|
+
const clientSessions = this.clientToSessions.get(clientId);
|
|
255
|
+
return clientSessions ? Array.from(clientSessions) : [];
|
|
256
|
+
}
|
|
257
|
+
trackClientSession(clientId, sessionId) {
|
|
258
|
+
let clientSessions = this.clientToSessions.get(clientId);
|
|
259
|
+
if (!clientSessions) {
|
|
260
|
+
clientSessions = new Set();
|
|
261
|
+
this.clientToSessions.set(clientId, clientSessions);
|
|
262
|
+
}
|
|
263
|
+
clientSessions.add(sessionId);
|
|
264
|
+
}
|
|
265
|
+
// ==========================================================================
|
|
266
|
+
// Broadcasting
|
|
267
|
+
// ==========================================================================
|
|
268
|
+
/**
|
|
269
|
+
* Broadcast a message to all clients in a session.
|
|
270
|
+
*/
|
|
271
|
+
broadcastToSession(sessionId, message, excludeClientId) {
|
|
272
|
+
const session = this.sessions.get(sessionId);
|
|
273
|
+
if (!session)
|
|
274
|
+
return;
|
|
275
|
+
const messageStr = JSON.stringify(message);
|
|
276
|
+
for (const [clientId, client] of session.clients) {
|
|
277
|
+
if (clientId === excludeClientId)
|
|
278
|
+
continue;
|
|
279
|
+
try {
|
|
280
|
+
if (client.ws.readyState === 1) {
|
|
281
|
+
// WebSocket.OPEN
|
|
282
|
+
client.ws.send(messageStr);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
catch (e) {
|
|
286
|
+
this.log(`Error broadcasting to client ${clientId}: ${e}`, 'warn');
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Send a message to a specific client in a session.
|
|
292
|
+
*/
|
|
293
|
+
sendToClient(sessionId, clientId, message) {
|
|
294
|
+
const session = this.sessions.get(sessionId);
|
|
295
|
+
if (!session)
|
|
296
|
+
return false;
|
|
297
|
+
const client = session.clients.get(clientId);
|
|
298
|
+
if (!client)
|
|
299
|
+
return false;
|
|
300
|
+
try {
|
|
301
|
+
if (client.ws.readyState === 1) {
|
|
302
|
+
client.ws.send(JSON.stringify(message));
|
|
303
|
+
return true;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
catch (e) {
|
|
307
|
+
this.log(`Error sending to client ${clientId}: ${e}`, 'warn');
|
|
308
|
+
}
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
// ==========================================================================
|
|
312
|
+
// History
|
|
313
|
+
// ==========================================================================
|
|
314
|
+
/**
|
|
315
|
+
* Append data to a session's history buffer.
|
|
316
|
+
*/
|
|
317
|
+
appendHistory(sessionId, data) {
|
|
318
|
+
const session = this.sessions.get(sessionId);
|
|
319
|
+
if (session && session.historyEnabled) {
|
|
320
|
+
session.historyBuffer.append(data);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Get history from a session.
|
|
325
|
+
*/
|
|
326
|
+
getHistory(sessionId, limit) {
|
|
327
|
+
const session = this.sessions.get(sessionId);
|
|
328
|
+
if (!session || !session.historyEnabled)
|
|
329
|
+
return '';
|
|
330
|
+
return session.historyBuffer.toString(limit);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Clear history for a session.
|
|
334
|
+
*/
|
|
335
|
+
clearHistory(sessionId) {
|
|
336
|
+
const session = this.sessions.get(sessionId);
|
|
337
|
+
if (session) {
|
|
338
|
+
session.historyBuffer.clear();
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
// ==========================================================================
|
|
342
|
+
// Activity Tracking
|
|
343
|
+
// ==========================================================================
|
|
344
|
+
/**
|
|
345
|
+
* Update last activity timestamp for a session.
|
|
346
|
+
*/
|
|
347
|
+
updateSessionActivity(sessionId) {
|
|
348
|
+
const session = this.sessions.get(sessionId);
|
|
349
|
+
if (session) {
|
|
350
|
+
session.lastActivity = new Date();
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* Update last activity for a client.
|
|
355
|
+
*/
|
|
356
|
+
updateClientActivity(sessionId, clientId) {
|
|
357
|
+
const session = this.sessions.get(sessionId);
|
|
358
|
+
if (session) {
|
|
359
|
+
session.lastActivity = new Date();
|
|
360
|
+
const client = session.clients.get(clientId);
|
|
361
|
+
if (client) {
|
|
362
|
+
client.lastActivity = new Date();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// ==========================================================================
|
|
367
|
+
// Orphan Handling
|
|
368
|
+
// ==========================================================================
|
|
369
|
+
handleOrphanedSession(session) {
|
|
370
|
+
session.orphanedAt = new Date();
|
|
371
|
+
this.log(`Session ${session.id} is now orphaned, starting cleanup timer`);
|
|
372
|
+
this.emit('sessionOrphaned', session.id);
|
|
373
|
+
// Start orphan timer
|
|
374
|
+
const timer = setTimeout(() => {
|
|
375
|
+
// Check if still orphaned
|
|
376
|
+
if (session.clients.size === 0) {
|
|
377
|
+
this.log(`Orphan timeout for session ${session.id}, closing`);
|
|
378
|
+
this.closeSession(session.id, 'orphan_timeout');
|
|
379
|
+
}
|
|
380
|
+
}, this.config.orphanTimeout);
|
|
381
|
+
this.orphanTimers.set(session.id, timer);
|
|
382
|
+
}
|
|
383
|
+
clearOrphanTimer(sessionId) {
|
|
384
|
+
const timer = this.orphanTimers.get(sessionId);
|
|
385
|
+
if (timer) {
|
|
386
|
+
clearTimeout(timer);
|
|
387
|
+
this.orphanTimers.delete(sessionId);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
// ==========================================================================
|
|
391
|
+
// Session Info
|
|
392
|
+
// ==========================================================================
|
|
393
|
+
/**
|
|
394
|
+
* Convert a session to SharedSessionInfo for client consumption.
|
|
395
|
+
*/
|
|
396
|
+
toSharedSessionInfo(session) {
|
|
397
|
+
return {
|
|
398
|
+
sessionId: session.id,
|
|
399
|
+
type: session.type,
|
|
400
|
+
shell: session.shell,
|
|
401
|
+
cwd: session.cwd,
|
|
402
|
+
cols: session.cols,
|
|
403
|
+
rows: session.rows,
|
|
404
|
+
createdAt: session.createdAt,
|
|
405
|
+
container: session.container,
|
|
406
|
+
clientCount: session.clients.size,
|
|
407
|
+
accepting: session.accepting,
|
|
408
|
+
ownerId: session.owner,
|
|
409
|
+
label: session.label,
|
|
410
|
+
historyEnabled: session.historyEnabled,
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
// ==========================================================================
|
|
414
|
+
// Cleanup
|
|
415
|
+
// ==========================================================================
|
|
416
|
+
/**
|
|
417
|
+
* Clean up all sessions and resources.
|
|
418
|
+
*/
|
|
419
|
+
cleanup() {
|
|
420
|
+
this.log('Cleaning up all sessions');
|
|
421
|
+
// Clear all orphan timers
|
|
422
|
+
for (const timer of this.orphanTimers.values()) {
|
|
423
|
+
clearTimeout(timer);
|
|
424
|
+
}
|
|
425
|
+
this.orphanTimers.clear();
|
|
426
|
+
// Close all sessions
|
|
427
|
+
for (const sessionId of this.sessions.keys()) {
|
|
428
|
+
this.closeSession(sessionId, 'cleanup');
|
|
429
|
+
}
|
|
430
|
+
this.clientToSessions.clear();
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Get manager statistics.
|
|
434
|
+
*/
|
|
435
|
+
getStats() {
|
|
436
|
+
let orphanedCount = 0;
|
|
437
|
+
for (const session of this.sessions.values()) {
|
|
438
|
+
if (session.orphanedAt)
|
|
439
|
+
orphanedCount++;
|
|
440
|
+
}
|
|
441
|
+
return {
|
|
442
|
+
sessionCount: this.sessions.size,
|
|
443
|
+
clientCount: this.clientToSessions.size,
|
|
444
|
+
orphanedCount,
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
//# sourceMappingURL=session-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-manager.js","sourceRoot":"","sources":["../../src/server/session-manager.ts"],"names":[],"mappings":"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"}
|