thinkncollab-shell 0.0.1 → 0.0.2
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/bin/thinknsh.js +3 -2
- package/package.json +8 -5
- package/src/commands/auth/login.js +77 -0
- package/src/commands/auth/logout.js +32 -0
- package/src/commands/auth/whoami.js +47 -0
- package/src/commands/index.js +104 -0
- package/src/commands/message/say.js +43 -0
- package/src/commands/room/join.js +68 -0
- package/src/commands/room/leave.js +33 -0
- package/src/commands/room/rooms.js +66 -0
- package/src/commands/shell/status.js +73 -0
- package/src/commands/team/invite.js +46 -0
- package/src/commands/team/myteam.js +78 -0
- package/src/commands/team/teammates.js +52 -0
- package/src/core/api-client.js +156 -0
- package/src/core/notification-window.js +135 -0
- package/src/core/shell.js +415 -854
- package/src/core/websocket.js +230 -292
package/src/core/websocket.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WebSocket Manager for ThinkNCollab Shell
|
|
3
|
-
*
|
|
3
|
+
* Uses thinknsh: prefixed events for terminal-specific communication
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
const { io } = require('socket.io-client');
|
|
@@ -9,377 +9,315 @@ const EventEmitter = require('events');
|
|
|
9
9
|
class WebSocketManager extends EventEmitter {
|
|
10
10
|
constructor(config = {}) {
|
|
11
11
|
super();
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
this.config = {
|
|
14
|
-
serverUrl:
|
|
14
|
+
serverUrl: config.serverUrl || 'https://thinkncollab.com',
|
|
15
15
|
reconnectAttempts: config.reconnectAttempts || 5,
|
|
16
|
-
reconnectDelay:
|
|
17
|
-
autoConnect: config.autoConnect || false,
|
|
16
|
+
reconnectDelay: config.reconnectDelay || 1000,
|
|
18
17
|
...config
|
|
19
18
|
};
|
|
20
|
-
|
|
21
|
-
this.socket
|
|
22
|
-
this.connected
|
|
23
|
-
this.
|
|
24
|
-
this.roomId
|
|
19
|
+
|
|
20
|
+
this.socket = null;
|
|
21
|
+
this.connected = false;
|
|
22
|
+
this.currentUser = null; // { userId, name, userType }
|
|
23
|
+
this.roomId = null;
|
|
25
24
|
this.reconnectCount = 0;
|
|
26
|
-
this.
|
|
27
|
-
this.messageQueue = [];
|
|
28
|
-
|
|
29
|
-
// Bind methods
|
|
30
|
-
this.connect = this.connect.bind(this);
|
|
31
|
-
this.disconnect = this.disconnect.bind(this);
|
|
32
|
-
this.joinRoom = this.joinRoom.bind(this);
|
|
33
|
-
this.leaveRoom = this.leaveRoom.bind(this);
|
|
34
|
-
this.sendMessage = this.sendMessage.bind(this);
|
|
35
|
-
this.sendNotification = this.sendNotification.bind(this);
|
|
25
|
+
this.messageQueue = [];
|
|
36
26
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
*/
|
|
27
|
+
|
|
28
|
+
// ─── Connect ──────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
41
30
|
connect(authToken = null) {
|
|
42
31
|
return new Promise((resolve, reject) => {
|
|
43
32
|
try {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
33
|
+
// Connect to /thinknsh namespace — isolated from web
|
|
34
|
+
this.socket = io(this.config.serverUrl + '/thinknsh', {
|
|
35
|
+
transports: ['websocket', 'polling'],
|
|
36
|
+
reconnection: true,
|
|
47
37
|
reconnectionAttempts: this.config.reconnectAttempts,
|
|
48
|
-
reconnectionDelay:
|
|
49
|
-
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
this.socket = io(this.config.serverUrl, options);
|
|
57
|
-
|
|
58
|
-
// Connection established
|
|
38
|
+
reconnectionDelay: this.config.reconnectDelay,
|
|
39
|
+
auth: authToken ? { token: authToken } : {},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const timeout = setTimeout(() => reject(new Error('Connection timeout')), 10000);
|
|
43
|
+
|
|
59
44
|
this.socket.on('connect', () => {
|
|
60
|
-
|
|
45
|
+
clearTimeout(timeout);
|
|
46
|
+
this.connected = true;
|
|
61
47
|
this.reconnectCount = 0;
|
|
62
|
-
this.
|
|
63
|
-
|
|
64
|
-
//
|
|
48
|
+
this._authToken = authToken;
|
|
49
|
+
|
|
50
|
+
// Announce terminal to backend — join personal notification room
|
|
51
|
+
if (this.currentUser) {
|
|
52
|
+
console.log('🖥️ Emitting thinknsh:connected for', this.currentUser.userId);
|
|
53
|
+
this.socket.emit('thinknsh:connected', {
|
|
54
|
+
userId: this.currentUser.userId,
|
|
55
|
+
userName: this.currentUser.name,
|
|
56
|
+
shellToken: authToken,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
65
60
|
this.processPendingMessages();
|
|
66
|
-
|
|
67
61
|
this.emit('connected', { socketId: this.socket.id });
|
|
68
62
|
resolve({ success: true, socketId: this.socket.id });
|
|
69
63
|
});
|
|
70
|
-
|
|
71
|
-
// Connection error
|
|
64
|
+
|
|
72
65
|
this.socket.on('connect_error', (error) => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
reject(new Error(`Failed to connect after ${this.config.reconnectAttempts} attempts`));
|
|
66
|
+
clearTimeout(timeout);
|
|
67
|
+
if (this.reconnectCount === 0) {
|
|
68
|
+
reject(new Error(`Cannot connect to ${this.config.serverUrl}`));
|
|
77
69
|
}
|
|
78
70
|
this.reconnectCount++;
|
|
71
|
+
this.emit('error', { message: error.message });
|
|
79
72
|
});
|
|
80
|
-
|
|
81
|
-
// Disconnection
|
|
73
|
+
|
|
82
74
|
this.socket.on('disconnect', (reason) => {
|
|
83
75
|
this.connected = false;
|
|
84
76
|
this.emit('disconnected', { reason });
|
|
85
|
-
|
|
86
|
-
if (reason === 'io server disconnect') {
|
|
87
|
-
// Server disconnected, don't reconnect
|
|
88
|
-
this.socket = null;
|
|
89
|
-
}
|
|
90
77
|
});
|
|
91
|
-
|
|
92
|
-
// Reconnection
|
|
78
|
+
|
|
93
79
|
this.socket.on('reconnect', (attemptNumber) => {
|
|
94
80
|
this.connected = true;
|
|
95
81
|
this.emit('reconnected', { attemptNumber });
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
this.joinRoom(this.roomId);
|
|
82
|
+
// Rejoin room after reconnect
|
|
83
|
+
if (this.roomId && this.currentUser) {
|
|
84
|
+
this._emitJoin(this.roomId);
|
|
100
85
|
}
|
|
101
86
|
});
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
87
|
+
|
|
88
|
+
this.setupEventHandlers(authToken);
|
|
89
|
+
|
|
106
90
|
} catch (error) {
|
|
107
91
|
reject(error);
|
|
108
92
|
}
|
|
109
93
|
});
|
|
110
94
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
//
|
|
117
|
-
this.socket.on('
|
|
95
|
+
|
|
96
|
+
// ─── thinknsh: event handlers ─────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
setupEventHandlers(authToken) {
|
|
99
|
+
|
|
100
|
+
// Terminal ready confirmed by server
|
|
101
|
+
this.socket.on('thinknsh:ready', (data) => {
|
|
102
|
+
this.emit('ready', data);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Room join confirmed
|
|
106
|
+
this.socket.on('thinknsh:joined', (data) => {
|
|
118
107
|
this.roomId = data.roomId;
|
|
119
108
|
this.emit('roomJoined', data);
|
|
120
109
|
});
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
this.emit('
|
|
110
|
+
|
|
111
|
+
// Incoming message from terminal or web
|
|
112
|
+
this.socket.on('thinknsh:message', (data) => {
|
|
113
|
+
this.emit('message', {
|
|
114
|
+
username: data.name,
|
|
115
|
+
userId: data.userId,
|
|
116
|
+
message: data.message,
|
|
117
|
+
source: data.source || 'web',
|
|
118
|
+
timestamp: data.timestamp,
|
|
119
|
+
});
|
|
125
120
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
121
|
+
|
|
122
|
+
// Also listen to standard chat-message (from web users)
|
|
123
|
+
this.socket.on('chat-message', (data) => {
|
|
124
|
+
this.emit('message', {
|
|
125
|
+
username: data.name,
|
|
126
|
+
userId: data.userId,
|
|
127
|
+
message: data.message,
|
|
128
|
+
source: data.source || 'web',
|
|
129
|
+
timestamp: data.timestamp,
|
|
130
|
+
});
|
|
129
131
|
});
|
|
130
|
-
|
|
131
|
-
//
|
|
132
|
-
this.socket.on('
|
|
133
|
-
this.emit('
|
|
132
|
+
|
|
133
|
+
// User joined from terminal
|
|
134
|
+
this.socket.on('thinknsh:userJoined', (data) => {
|
|
135
|
+
this.emit('userJoined', { username: data.name, source: 'shell' });
|
|
134
136
|
});
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
137
|
+
|
|
138
|
+
// User joined from web
|
|
139
|
+
this.socket.on('user-joined', (name) => {
|
|
140
|
+
this.emit('userJoined', { username: name, source: 'web' });
|
|
138
141
|
});
|
|
139
|
-
|
|
140
|
-
// User
|
|
141
|
-
this.socket.on('user
|
|
142
|
-
this.emit('
|
|
142
|
+
|
|
143
|
+
// User left
|
|
144
|
+
this.socket.on('user-left', (name) => {
|
|
145
|
+
this.emit('userLeft', { username: name });
|
|
143
146
|
});
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
+
|
|
148
|
+
// User list updated
|
|
149
|
+
this.socket.on('user-list', (users) => {
|
|
150
|
+
this.emit('userList', { users });
|
|
147
151
|
});
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
152
|
+
|
|
153
|
+
// Notifications from NotificationEngine
|
|
154
|
+
this.socket.on('new-notification', (notification) => {
|
|
155
|
+
this.emit('notification', {
|
|
156
|
+
type: notification.type || 'info',
|
|
157
|
+
title: notification.type || 'Notification',
|
|
158
|
+
message: notification.message || '',
|
|
159
|
+
meta: notification.meta || {},
|
|
160
|
+
});
|
|
151
161
|
});
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
this.socket.on('
|
|
155
|
-
this.emit('
|
|
162
|
+
|
|
163
|
+
// Terminal status (online/offline) — website sends this
|
|
164
|
+
this.socket.on('thinknsh:status', (data) => {
|
|
165
|
+
this.emit('shellStatus', data);
|
|
156
166
|
});
|
|
157
|
-
|
|
158
|
-
//
|
|
159
|
-
this.socket.on('
|
|
160
|
-
|
|
167
|
+
|
|
168
|
+
// ── new-notification from NotificationEngine → forward to TCP window ──
|
|
169
|
+
this.socket.on('new-notification', (data) => {
|
|
170
|
+
// This goes to shell.js pushNotification → TCP → notification window
|
|
171
|
+
this.emit('notification', {
|
|
172
|
+
type: data.type || 'notification',
|
|
173
|
+
level: data.type || 'info',
|
|
174
|
+
title: data.type || 'Notification',
|
|
175
|
+
message: data.message || '',
|
|
176
|
+
taskTitle: data.taskTitle || data.meta?.taskTitle || '',
|
|
177
|
+
assignedBy: data.assignedBy || data.meta?.assignedBy || '',
|
|
178
|
+
});
|
|
161
179
|
});
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
180
|
+
|
|
181
|
+
// Notification list response
|
|
182
|
+
this.socket.on('thinknsh:notifications', (data) => {
|
|
183
|
+
this.emit('notificationList', data.notifications);
|
|
165
184
|
});
|
|
166
|
-
|
|
167
|
-
// Error
|
|
185
|
+
|
|
186
|
+
// Error from server
|
|
187
|
+
this.socket.on('thinknsh:error', (data) => {
|
|
188
|
+
this.emit('serverError', data);
|
|
189
|
+
});
|
|
190
|
+
|
|
168
191
|
this.socket.on('error', (data) => {
|
|
169
192
|
this.emit('serverError', data);
|
|
170
193
|
});
|
|
171
194
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
this.socket
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
this.emit('disconnected', { reason: 'manual' });
|
|
195
|
+
|
|
196
|
+
// ─── Set user (call after login) ──────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
setUser(user, token = null) {
|
|
199
|
+
this.currentUser = user;
|
|
200
|
+
// If already connected, announce now
|
|
201
|
+
if (this.connected && this.socket) {
|
|
202
|
+
this.socket.emit('thinknsh:connected', {
|
|
203
|
+
userId: user.userId,
|
|
204
|
+
shellToken: token,
|
|
205
|
+
});
|
|
184
206
|
}
|
|
185
207
|
}
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
joinRoom(roomId, password = null) {
|
|
208
|
+
|
|
209
|
+
// ─── Join room ────────────────────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
joinRoom(roomId) {
|
|
191
212
|
return new Promise((resolve, reject) => {
|
|
192
|
-
if (!this.connected || !this.socket)
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
if (password) payload.password = password;
|
|
199
|
-
|
|
200
|
-
this.socket.emit('room:join', payload);
|
|
201
|
-
|
|
202
|
-
// Wait for response
|
|
203
|
-
const timeout = setTimeout(() => {
|
|
204
|
-
reject(new Error('Join room timeout'));
|
|
205
|
-
}, 5000);
|
|
206
|
-
|
|
207
|
-
this.socket.once('room:joined', (data) => {
|
|
213
|
+
if (!this.connected || !this.socket) return reject(new Error('Not connected'));
|
|
214
|
+
if (!this.currentUser) return reject(new Error('Not logged in'));
|
|
215
|
+
|
|
216
|
+
const timeout = setTimeout(() => reject(new Error('Join timeout')), 5000);
|
|
217
|
+
|
|
218
|
+
this.socket.once('thinknsh:joined', (data) => {
|
|
208
219
|
clearTimeout(timeout);
|
|
209
220
|
this.roomId = data.roomId;
|
|
210
221
|
resolve(data);
|
|
211
222
|
});
|
|
212
|
-
|
|
213
|
-
this.
|
|
214
|
-
clearTimeout(timeout);
|
|
215
|
-
reject(new Error(data.message));
|
|
216
|
-
});
|
|
223
|
+
|
|
224
|
+
this._emitJoin(roomId);
|
|
217
225
|
});
|
|
218
226
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
227
|
+
|
|
228
|
+
_emitJoin(roomId) {
|
|
229
|
+
this.socket.emit('thinknsh:join', {
|
|
230
|
+
roomId,
|
|
231
|
+
userId: this.currentUser.userId,
|
|
232
|
+
name: this.currentUser.name,
|
|
233
|
+
userType: this.currentUser.userType || 'User',
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// ─── Leave room ───────────────────────────────────────────────────────────
|
|
238
|
+
|
|
223
239
|
leaveRoom() {
|
|
224
|
-
if (
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return new Promise((resolve) => {
|
|
229
|
-
this.socket.emit('room:leave', { roomId: this.roomId });
|
|
240
|
+
if (this.socket && this.roomId) {
|
|
241
|
+
this.socket.emit('leave-room', { roomId: this.roomId });
|
|
230
242
|
this.roomId = null;
|
|
231
|
-
|
|
232
|
-
});
|
|
243
|
+
}
|
|
244
|
+
return Promise.resolve({ success: true });
|
|
233
245
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
sendMessage(message, type = 'text') {
|
|
246
|
+
|
|
247
|
+
// ─── Send message ─────────────────────────────────────────────────────────
|
|
248
|
+
|
|
249
|
+
sendMessage(message) {
|
|
239
250
|
if (!this.connected || !this.socket) {
|
|
240
|
-
|
|
241
|
-
this.messageQueue.push({ message, type });
|
|
251
|
+
this.messageQueue.push(message);
|
|
242
252
|
return Promise.resolve({ queued: true });
|
|
243
253
|
}
|
|
244
|
-
|
|
245
|
-
if (!this.
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
type,
|
|
254
|
-
timestamp: new Date().toISOString()
|
|
255
|
-
};
|
|
256
|
-
|
|
257
|
-
this.socket.emit('message:send', payload);
|
|
258
|
-
resolve({ success: true, id: `msg_${Date.now()}` });
|
|
254
|
+
if (!this.roomId) return Promise.reject(new Error('Not in a room — run: join <room-id>'));
|
|
255
|
+
if (!this.currentUser) return Promise.reject(new Error('Not logged in — run: login'));
|
|
256
|
+
|
|
257
|
+
this.socket.emit('thinknsh:message', {
|
|
258
|
+
roomId: this.roomId,
|
|
259
|
+
userId: this.currentUser.userId,
|
|
260
|
+
name: this.currentUser.name,
|
|
261
|
+
userType: this.currentUser.userType || 'User',
|
|
262
|
+
message,
|
|
259
263
|
});
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
/**
|
|
263
|
-
* Send notification to room/users
|
|
264
|
-
*/
|
|
265
|
-
sendNotification(notification, target = 'room') {
|
|
266
|
-
if (!this.connected || !this.socket) {
|
|
267
|
-
return Promise.reject(new Error('WebSocket not connected'));
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const payload = {
|
|
271
|
-
type: notification.type || 'info',
|
|
272
|
-
title: notification.title,
|
|
273
|
-
message: notification.message,
|
|
274
|
-
data: notification.data,
|
|
275
|
-
target: target === 'room' ? this.roomId : target,
|
|
276
|
-
timestamp: new Date().toISOString()
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
this.socket.emit('notification:send', payload);
|
|
280
|
-
|
|
264
|
+
|
|
281
265
|
return Promise.resolve({ success: true });
|
|
282
266
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
this.socket.emit('terminal:share', {
|
|
293
|
-
roomId: this.roomId,
|
|
294
|
-
command,
|
|
295
|
-
output,
|
|
296
|
-
timestamp: new Date().toISOString()
|
|
297
|
-
});
|
|
267
|
+
|
|
268
|
+
// ─── Get unread notifications ─────────────────────────────────────────────
|
|
269
|
+
|
|
270
|
+
getNotifications() {
|
|
271
|
+
if (!this.connected || !this.currentUser) return;
|
|
272
|
+
this.socket.emit('thinknsh:getNotifications', { userId: this.currentUser.userId });
|
|
298
273
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
this.socket.emit('user:typing', {
|
|
309
|
-
roomId: this.roomId,
|
|
310
|
-
isTyping
|
|
274
|
+
|
|
275
|
+
markNotificationsRead(notificationIds = []) {
|
|
276
|
+
if (!this.connected || !this.currentUser) return;
|
|
277
|
+
this.socket.emit('thinknsh:markRead', {
|
|
278
|
+
userId: this.currentUser.userId,
|
|
279
|
+
notificationIds,
|
|
311
280
|
});
|
|
312
281
|
}
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
return new Promise((resolve) => {
|
|
323
|
-
this.socket.emit('room:getParticipants', { roomId: this.roomId });
|
|
324
|
-
|
|
325
|
-
this.socket.once('room:participants', (data) => {
|
|
326
|
-
resolve(data.participants);
|
|
327
|
-
});
|
|
282
|
+
|
|
283
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────
|
|
284
|
+
|
|
285
|
+
joinUserRoom(userId) {
|
|
286
|
+
if (!this.socket || !userId) return;
|
|
287
|
+
this.socket.emit('thinknsh:connected', {
|
|
288
|
+
userId,
|
|
289
|
+
userName: this.currentUser?.name || '',
|
|
290
|
+
shellToken: this._token || null,
|
|
328
291
|
});
|
|
329
292
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
if (!this.connected || !this.socket || !this.roomId) {
|
|
336
|
-
return Promise.reject(new Error('Not connected to a room'));
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return new Promise((resolve) => {
|
|
340
|
-
this.socket.emit('message:getHistory', {
|
|
341
|
-
roomId: this.roomId,
|
|
342
|
-
limit
|
|
343
|
-
});
|
|
344
|
-
|
|
345
|
-
this.socket.once('message:history', (data) => {
|
|
346
|
-
resolve(data.messages);
|
|
347
|
-
});
|
|
348
|
-
});
|
|
293
|
+
|
|
294
|
+
sendTyping() {} // add later if needed
|
|
295
|
+
|
|
296
|
+
ping() {
|
|
297
|
+
if (this.connected && this.socket) this.socket.emit('ping');
|
|
349
298
|
}
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Process pending messages after reconnection
|
|
353
|
-
*/
|
|
299
|
+
|
|
354
300
|
processPendingMessages() {
|
|
355
|
-
if (this.messageQueue.length > 0) {
|
|
356
|
-
this.messageQueue.forEach(
|
|
357
|
-
this.sendMessage(item.message, item.type);
|
|
358
|
-
});
|
|
301
|
+
if (this.messageQueue.length > 0 && this.roomId && this.currentUser) {
|
|
302
|
+
this.messageQueue.forEach(msg => this.sendMessage(msg));
|
|
359
303
|
this.messageQueue = [];
|
|
360
304
|
}
|
|
361
305
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
* Get current room info
|
|
372
|
-
*/
|
|
373
|
-
getCurrentRoom() {
|
|
374
|
-
return this.roomId;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Get socket ID
|
|
379
|
-
*/
|
|
380
|
-
getSocketId() {
|
|
381
|
-
return this.userId;
|
|
306
|
+
|
|
307
|
+
disconnect() {
|
|
308
|
+
if (this.socket) {
|
|
309
|
+
this.socket.disconnect();
|
|
310
|
+
this.socket = null;
|
|
311
|
+
this.connected = false;
|
|
312
|
+
this.currentUser = null;
|
|
313
|
+
this.roomId = null;
|
|
314
|
+
}
|
|
382
315
|
}
|
|
316
|
+
|
|
317
|
+
isConnected() { return this.connected && !!this.socket?.connected; }
|
|
318
|
+
getCurrentRoom() { return this.roomId; }
|
|
319
|
+
getSocketId() { return this.socket?.id || null; }
|
|
320
|
+
getParticipants() { return Promise.resolve([]); }
|
|
383
321
|
}
|
|
384
322
|
|
|
385
323
|
module.exports = WebSocketManager;
|