|
|
|
|
@@ -1,18 +1,8 @@
|
|
|
|
|
import { connectedUsers } from './state';
|
|
|
|
|
import { ConnectedUser } from './types';
|
|
|
|
|
import {
|
|
|
|
|
broadcastToServer,
|
|
|
|
|
findUserByOderId,
|
|
|
|
|
getServerIdsForOderId,
|
|
|
|
|
getUniqueUsersInServer,
|
|
|
|
|
isOderIdConnectedToServer
|
|
|
|
|
} from './broadcast';
|
|
|
|
|
import { broadcastToServer, findUserByOderId, getServerIdsForOderId, getUniqueUsersInServer, isOderIdConnectedToServer } from './broadcast';
|
|
|
|
|
import { authorizeWebSocketJoin } from '../services/server-access.service';
|
|
|
|
|
import {
|
|
|
|
|
getPluginRequirementsSnapshot,
|
|
|
|
|
PluginSupportError,
|
|
|
|
|
validatePluginEventEnvelope
|
|
|
|
|
} from '../services/plugin-support.service';
|
|
|
|
|
import { getPluginRequirementsSnapshot, PluginSupportError, validatePluginEventEnvelope } from '../services/plugin-support.service';
|
|
|
|
|
|
|
|
|
|
interface WsMessage {
|
|
|
|
|
[key: string]: unknown;
|
|
|
|
|
@@ -36,9 +26,7 @@ function normalizeDescription(value: unknown): string | undefined {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function normalizeProfileUpdatedAt(value: unknown): number | undefined {
|
|
|
|
|
return typeof value === 'number' && Number.isFinite(value) && value > 0
|
|
|
|
|
? value
|
|
|
|
|
: undefined;
|
|
|
|
|
return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function readMessageId(value: unknown): string | undefined {
|
|
|
|
|
@@ -57,37 +45,40 @@ function readMessageId(value: unknown): string | undefined {
|
|
|
|
|
|
|
|
|
|
function sendPluginError(user: ConnectedUser, error: unknown, message: WsMessage): void {
|
|
|
|
|
if (error instanceof PluginSupportError) {
|
|
|
|
|
user.ws.send(JSON.stringify({
|
|
|
|
|
type: 'plugin_error',
|
|
|
|
|
serverId: typeof message['serverId'] === 'string' ? message['serverId'] : undefined,
|
|
|
|
|
pluginId: typeof message['pluginId'] === 'string' ? message['pluginId'] : undefined,
|
|
|
|
|
eventName: typeof message['eventName'] === 'string' ? message['eventName'] : undefined,
|
|
|
|
|
eventId: typeof message['eventId'] === 'string' ? message['eventId'] : undefined,
|
|
|
|
|
code: error.code,
|
|
|
|
|
message: error.message
|
|
|
|
|
}));
|
|
|
|
|
user.ws.send(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
type: 'plugin_error',
|
|
|
|
|
serverId: typeof message['serverId'] === 'string' ? message['serverId'] : undefined,
|
|
|
|
|
pluginId: typeof message['pluginId'] === 'string' ? message['pluginId'] : undefined,
|
|
|
|
|
eventName: typeof message['eventName'] === 'string' ? message['eventName'] : undefined,
|
|
|
|
|
eventId: typeof message['eventId'] === 'string' ? message['eventId'] : undefined,
|
|
|
|
|
code: error.code,
|
|
|
|
|
message: error.message
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.error('Unhandled plugin websocket error:', error);
|
|
|
|
|
user.ws.send(JSON.stringify({
|
|
|
|
|
type: 'plugin_error',
|
|
|
|
|
code: 'INTERNAL_ERROR',
|
|
|
|
|
message: 'Internal server error'
|
|
|
|
|
}));
|
|
|
|
|
user.ws.send(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
type: 'plugin_error',
|
|
|
|
|
code: 'INTERNAL_ERROR',
|
|
|
|
|
message: 'Internal server error'
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Sends the current user list for a given server to a single connected user. */
|
|
|
|
|
function sendServerUsers(user: ConnectedUser, serverId: string): void {
|
|
|
|
|
const users = getUniqueUsersInServer(serverId, user.oderId)
|
|
|
|
|
.map(cu => ({
|
|
|
|
|
oderId: cu.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(cu.displayName),
|
|
|
|
|
description: cu.description,
|
|
|
|
|
profileUpdatedAt: cu.profileUpdatedAt,
|
|
|
|
|
status: cu.status ?? 'online'
|
|
|
|
|
}));
|
|
|
|
|
const users = getUniqueUsersInServer(serverId, user.oderId).map((cu) => ({
|
|
|
|
|
oderId: cu.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(cu.displayName),
|
|
|
|
|
description: cu.description,
|
|
|
|
|
profileUpdatedAt: cu.profileUpdatedAt,
|
|
|
|
|
status: cu.status ?? 'online'
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
user.ws.send(JSON.stringify({ type: 'server_users', serverId, users }));
|
|
|
|
|
}
|
|
|
|
|
@@ -96,11 +87,13 @@ async function sendPluginRequirements(user: ConnectedUser, serverId: string): Pr
|
|
|
|
|
try {
|
|
|
|
|
const snapshot = await getPluginRequirementsSnapshot(serverId);
|
|
|
|
|
|
|
|
|
|
user.ws.send(JSON.stringify({
|
|
|
|
|
type: 'plugin_requirements',
|
|
|
|
|
serverId,
|
|
|
|
|
snapshot
|
|
|
|
|
}));
|
|
|
|
|
user.ws.send(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
type: 'plugin_requirements',
|
|
|
|
|
serverId,
|
|
|
|
|
snapshot
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
sendPluginError(user, error, { type: 'plugin_requirements', serverId });
|
|
|
|
|
}
|
|
|
|
|
@@ -128,41 +121,42 @@ function handleIdentify(user: ConnectedUser, message: WsMessage, connectionId: s
|
|
|
|
|
connectedUsers.set(connectionId, user);
|
|
|
|
|
console.log(`User identified: ${user.displayName} (${user.oderId})`);
|
|
|
|
|
|
|
|
|
|
if (
|
|
|
|
|
user.displayName === previousDisplayName
|
|
|
|
|
&& user.description === previousDescription
|
|
|
|
|
&& user.profileUpdatedAt === previousProfileUpdatedAt
|
|
|
|
|
) {
|
|
|
|
|
if (user.displayName === previousDisplayName && user.description === previousDescription && user.profileUpdatedAt === previousProfileUpdatedAt) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const serverId of user.serverIds) {
|
|
|
|
|
broadcastToServer(serverId, {
|
|
|
|
|
type: 'user_joined',
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(user.displayName),
|
|
|
|
|
description: user.description,
|
|
|
|
|
profileUpdatedAt: user.profileUpdatedAt,
|
|
|
|
|
status: user.status ?? 'online',
|
|
|
|
|
serverId
|
|
|
|
|
}, user.oderId);
|
|
|
|
|
broadcastToServer(
|
|
|
|
|
serverId,
|
|
|
|
|
{
|
|
|
|
|
type: 'user_joined',
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(user.displayName),
|
|
|
|
|
description: user.description,
|
|
|
|
|
profileUpdatedAt: user.profileUpdatedAt,
|
|
|
|
|
status: user.status ?? 'online',
|
|
|
|
|
serverId
|
|
|
|
|
},
|
|
|
|
|
user.oderId
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleJoinServer(user: ConnectedUser, message: WsMessage, connectionId: string): Promise<void> {
|
|
|
|
|
const sid = readMessageId(message['serverId']);
|
|
|
|
|
|
|
|
|
|
if (!sid)
|
|
|
|
|
return;
|
|
|
|
|
if (!sid) return;
|
|
|
|
|
|
|
|
|
|
const authorization = await authorizeWebSocketJoin(sid, user.oderId);
|
|
|
|
|
|
|
|
|
|
if (!authorization.allowed) {
|
|
|
|
|
user.ws.send(JSON.stringify({
|
|
|
|
|
type: 'access_denied',
|
|
|
|
|
serverId: sid,
|
|
|
|
|
reason: authorization.reason
|
|
|
|
|
}));
|
|
|
|
|
user.ws.send(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
type: 'access_denied',
|
|
|
|
|
serverId: sid,
|
|
|
|
|
reason: authorization.reason
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -174,31 +168,34 @@ async function handleJoinServer(user: ConnectedUser, message: WsMessage, connect
|
|
|
|
|
user.viewedServerId = sid;
|
|
|
|
|
connectedUsers.set(connectionId, user);
|
|
|
|
|
console.log(
|
|
|
|
|
`User ${normalizeDisplayName(user.displayName)} (${user.oderId}) joined server ${sid} `
|
|
|
|
|
+ `(newConnection=${isNewConnectionMembership}, newIdentity=${isNewIdentityMembership})`
|
|
|
|
|
`User ${normalizeDisplayName(user.displayName)} (${user.oderId}) joined server ${sid} ` +
|
|
|
|
|
`(newConnection=${isNewConnectionMembership}, newIdentity=${isNewIdentityMembership})`
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
sendServerUsers(user, sid);
|
|
|
|
|
await sendPluginRequirements(user, sid);
|
|
|
|
|
|
|
|
|
|
if (isNewIdentityMembership) {
|
|
|
|
|
broadcastToServer(sid, {
|
|
|
|
|
type: 'user_joined',
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(user.displayName),
|
|
|
|
|
description: user.description,
|
|
|
|
|
profileUpdatedAt: user.profileUpdatedAt,
|
|
|
|
|
status: user.status ?? 'online',
|
|
|
|
|
serverId: sid
|
|
|
|
|
}, user.oderId);
|
|
|
|
|
broadcastToServer(
|
|
|
|
|
sid,
|
|
|
|
|
{
|
|
|
|
|
type: 'user_joined',
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(user.displayName),
|
|
|
|
|
description: user.description,
|
|
|
|
|
profileUpdatedAt: user.profileUpdatedAt,
|
|
|
|
|
status: user.status ?? 'online',
|
|
|
|
|
serverId: sid
|
|
|
|
|
},
|
|
|
|
|
user.oderId
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handleViewServer(user: ConnectedUser, message: WsMessage, connectionId: string): Promise<void> {
|
|
|
|
|
const viewSid = readMessageId(message['serverId']);
|
|
|
|
|
|
|
|
|
|
if (!viewSid)
|
|
|
|
|
return;
|
|
|
|
|
if (!viewSid) return;
|
|
|
|
|
|
|
|
|
|
if (!user.serverIds.has(viewSid)) {
|
|
|
|
|
return;
|
|
|
|
|
@@ -215,13 +212,11 @@ async function handleViewServer(user: ConnectedUser, message: WsMessage, connect
|
|
|
|
|
function handleLeaveServer(user: ConnectedUser, message: WsMessage, connectionId: string): void {
|
|
|
|
|
const leaveSid = readMessageId(message['serverId']) ?? user.viewedServerId;
|
|
|
|
|
|
|
|
|
|
if (!leaveSid)
|
|
|
|
|
return;
|
|
|
|
|
if (!leaveSid) return;
|
|
|
|
|
|
|
|
|
|
user.serverIds.delete(leaveSid);
|
|
|
|
|
|
|
|
|
|
if (user.viewedServerId === leaveSid)
|
|
|
|
|
user.viewedServerId = undefined;
|
|
|
|
|
if (user.viewedServerId === leaveSid) user.viewedServerId = undefined;
|
|
|
|
|
|
|
|
|
|
connectedUsers.set(connectionId, user);
|
|
|
|
|
|
|
|
|
|
@@ -231,13 +226,17 @@ function handleLeaveServer(user: ConnectedUser, message: WsMessage, connectionId
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
broadcastToServer(leaveSid, {
|
|
|
|
|
type: 'user_left',
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(user.displayName),
|
|
|
|
|
serverId: leaveSid,
|
|
|
|
|
serverIds: remainingServerIds
|
|
|
|
|
}, user.oderId);
|
|
|
|
|
broadcastToServer(
|
|
|
|
|
leaveSid,
|
|
|
|
|
{
|
|
|
|
|
type: 'user_left',
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(user.displayName),
|
|
|
|
|
serverId: leaveSid,
|
|
|
|
|
serverIds: remainingServerIds
|
|
|
|
|
},
|
|
|
|
|
user.oderId
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function forwardRtcMessage(user: ConnectedUser, message: WsMessage): void {
|
|
|
|
|
@@ -253,7 +252,7 @@ function forwardRtcMessage(user: ConnectedUser, message: WsMessage): void {
|
|
|
|
|
} else {
|
|
|
|
|
console.log(
|
|
|
|
|
`Target user ${targetUserId} not found. Connected users:`,
|
|
|
|
|
Array.from(connectedUsers.values()).map(cu => ({ oderId: cu.oderId, displayName: cu.displayName }))
|
|
|
|
|
Array.from(connectedUsers.values()).map((cu) => ({ oderId: cu.oderId, displayName: cu.displayName }))
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@@ -275,62 +274,104 @@ function handleChatMessage(user: ConnectedUser, message: WsMessage): void {
|
|
|
|
|
|
|
|
|
|
function handleTyping(user: ConnectedUser, message: WsMessage): void {
|
|
|
|
|
const typingSid = (message['serverId'] as string | undefined) ?? user.viewedServerId;
|
|
|
|
|
const channelId = typeof message['channelId'] === 'string' && message['channelId'].trim()
|
|
|
|
|
? message['channelId'].trim()
|
|
|
|
|
: 'general';
|
|
|
|
|
const channelId = typeof message['channelId'] === 'string' && message['channelId'].trim() ? message['channelId'].trim() : 'general';
|
|
|
|
|
|
|
|
|
|
if (typingSid && user.serverIds.has(typingSid)) {
|
|
|
|
|
broadcastToServer(typingSid, {
|
|
|
|
|
type: 'user_typing',
|
|
|
|
|
serverId: typingSid,
|
|
|
|
|
channelId,
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
displayName: user.displayName
|
|
|
|
|
}, user.oderId);
|
|
|
|
|
broadcastToServer(
|
|
|
|
|
typingSid,
|
|
|
|
|
{
|
|
|
|
|
type: 'user_typing',
|
|
|
|
|
serverId: typingSid,
|
|
|
|
|
channelId,
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
displayName: user.displayName
|
|
|
|
|
},
|
|
|
|
|
user.oderId
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const VALID_STATUSES = new Set([
|
|
|
|
|
'online',
|
|
|
|
|
'away',
|
|
|
|
|
'busy',
|
|
|
|
|
'offline'
|
|
|
|
|
]);
|
|
|
|
|
const VALID_STATUSES = new Set(['online', 'away', 'busy', 'offline']);
|
|
|
|
|
|
|
|
|
|
function handleStatusUpdate(user: ConnectedUser, message: WsMessage, connectionId: string): void {
|
|
|
|
|
const status = typeof message['status'] === 'string' ? message['status'] : undefined;
|
|
|
|
|
|
|
|
|
|
if (!status || !VALID_STATUSES.has(status))
|
|
|
|
|
return;
|
|
|
|
|
if (!status || !VALID_STATUSES.has(status)) return;
|
|
|
|
|
|
|
|
|
|
user.status = status as ConnectedUser['status'];
|
|
|
|
|
connectedUsers.set(connectionId, user);
|
|
|
|
|
console.log(`User ${normalizeDisplayName(user.displayName)} (${user.oderId}) status -> ${status}`);
|
|
|
|
|
|
|
|
|
|
for (const serverId of user.serverIds) {
|
|
|
|
|
broadcastToServer(serverId, {
|
|
|
|
|
type: 'status_update',
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
status
|
|
|
|
|
}, user.oderId);
|
|
|
|
|
broadcastToServer(
|
|
|
|
|
serverId,
|
|
|
|
|
{
|
|
|
|
|
type: 'status_update',
|
|
|
|
|
oderId: user.oderId,
|
|
|
|
|
status
|
|
|
|
|
},
|
|
|
|
|
user.oderId
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleServerIconAvailable(user: ConnectedUser, message: WsMessage, connectionId: string): void {
|
|
|
|
|
const serverId = readMessageId(message['serverId']);
|
|
|
|
|
const iconUpdatedAt = typeof message['iconUpdatedAt'] === 'number' && Number.isFinite(message['iconUpdatedAt']) ? message['iconUpdatedAt'] : 0;
|
|
|
|
|
|
|
|
|
|
if (!serverId || iconUpdatedAt <= 0 || !user.serverIds.has(serverId)) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const availableIcons = user.serverIconUpdatedAtByServerId ?? new Map<string, number>();
|
|
|
|
|
|
|
|
|
|
availableIcons.set(serverId, iconUpdatedAt);
|
|
|
|
|
user.serverIconUpdatedAtByServerId = availableIcons;
|
|
|
|
|
connectedUsers.set(connectionId, user);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleServerIconSyncRequest(user: ConnectedUser, message: WsMessage): void {
|
|
|
|
|
const serverId = readMessageId(message['serverId']);
|
|
|
|
|
const localUpdatedAt = typeof message['iconUpdatedAt'] === 'number' && Number.isFinite(message['iconUpdatedAt']) ? message['iconUpdatedAt'] : 0;
|
|
|
|
|
|
|
|
|
|
if (!serverId) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const users = getUniqueUsersInServer(serverId, user.oderId)
|
|
|
|
|
.filter((candidate) => (candidate.serverIconUpdatedAtByServerId?.get(serverId) ?? 0) > localUpdatedAt)
|
|
|
|
|
.map((candidate) => ({
|
|
|
|
|
oderId: candidate.oderId,
|
|
|
|
|
displayName: normalizeDisplayName(candidate.displayName),
|
|
|
|
|
description: candidate.description,
|
|
|
|
|
profileUpdatedAt: candidate.profileUpdatedAt,
|
|
|
|
|
status: candidate.status ?? 'online'
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
if (users.length === 0) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
user.ws.send(JSON.stringify({ type: 'server_icon_sync_peers', serverId, users }));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function handlePluginEvent(user: ConnectedUser, message: WsMessage): Promise<void> {
|
|
|
|
|
const serverId = readMessageId(message['serverId']) ?? user.viewedServerId;
|
|
|
|
|
const pluginId = readMessageId(message['pluginId']);
|
|
|
|
|
const eventName = readMessageId(message['eventName']);
|
|
|
|
|
|
|
|
|
|
if (!serverId || !pluginId || !eventName || !user.serverIds.has(serverId)) {
|
|
|
|
|
user.ws.send(JSON.stringify({
|
|
|
|
|
type: 'plugin_error',
|
|
|
|
|
serverId,
|
|
|
|
|
pluginId,
|
|
|
|
|
eventName,
|
|
|
|
|
eventId: typeof message['eventId'] === 'string' ? message['eventId'] : undefined,
|
|
|
|
|
code: 'INVALID_PLUGIN_EVENT',
|
|
|
|
|
message: 'Plugin event is missing required fields or server membership'
|
|
|
|
|
}));
|
|
|
|
|
user.ws.send(
|
|
|
|
|
JSON.stringify({
|
|
|
|
|
type: 'plugin_error',
|
|
|
|
|
serverId,
|
|
|
|
|
pluginId,
|
|
|
|
|
eventName,
|
|
|
|
|
eventId: typeof message['eventId'] === 'string' ? message['eventId'] : undefined,
|
|
|
|
|
code: 'INVALID_PLUGIN_EVENT',
|
|
|
|
|
message: 'Plugin event is missing required fields or server membership'
|
|
|
|
|
})
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@@ -346,17 +387,21 @@ async function handlePluginEvent(user: ConnectedUser, message: WsMessage): Promi
|
|
|
|
|
sourcePluginUserId: typeof message['sourcePluginUserId'] === 'string' ? message['sourcePluginUserId'] : undefined
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
broadcastToServer(serverId, {
|
|
|
|
|
type: 'plugin_event',
|
|
|
|
|
broadcastToServer(
|
|
|
|
|
serverId,
|
|
|
|
|
pluginId,
|
|
|
|
|
eventName,
|
|
|
|
|
eventId: typeof message['eventId'] === 'string' ? message['eventId'] : undefined,
|
|
|
|
|
payload: message['payload'],
|
|
|
|
|
sourcePluginUserId: typeof message['sourcePluginUserId'] === 'string' ? message['sourcePluginUserId'] : undefined,
|
|
|
|
|
sourceUserId: user.oderId,
|
|
|
|
|
emittedAt: Date.now()
|
|
|
|
|
}, user.oderId);
|
|
|
|
|
{
|
|
|
|
|
type: 'plugin_event',
|
|
|
|
|
serverId,
|
|
|
|
|
pluginId,
|
|
|
|
|
eventName,
|
|
|
|
|
eventId: typeof message['eventId'] === 'string' ? message['eventId'] : undefined,
|
|
|
|
|
payload: message['payload'],
|
|
|
|
|
sourcePluginUserId: typeof message['sourcePluginUserId'] === 'string' ? message['sourcePluginUserId'] : undefined,
|
|
|
|
|
sourceUserId: user.oderId,
|
|
|
|
|
emittedAt: Date.now()
|
|
|
|
|
},
|
|
|
|
|
user.oderId
|
|
|
|
|
);
|
|
|
|
|
} catch (error) {
|
|
|
|
|
sendPluginError(user, error, message);
|
|
|
|
|
}
|
|
|
|
|
@@ -365,8 +410,7 @@ async function handlePluginEvent(user: ConnectedUser, message: WsMessage): Promi
|
|
|
|
|
export async function handleWebSocketMessage(connectionId: string, message: WsMessage): Promise<void> {
|
|
|
|
|
const user = connectedUsers.get(connectionId);
|
|
|
|
|
|
|
|
|
|
if (!user)
|
|
|
|
|
return;
|
|
|
|
|
if (!user) return;
|
|
|
|
|
|
|
|
|
|
user.lastPong = Date.now();
|
|
|
|
|
connectedUsers.set(connectionId, user);
|
|
|
|
|
@@ -394,6 +438,8 @@ export async function handleWebSocketMessage(connectionId: string, message: WsMe
|
|
|
|
|
case 'offer':
|
|
|
|
|
case 'answer':
|
|
|
|
|
case 'ice_candidate':
|
|
|
|
|
case 'server_icon_peer_request':
|
|
|
|
|
case 'server_icon_peer_data':
|
|
|
|
|
forwardRtcMessage(user, message);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
@@ -409,6 +455,14 @@ export async function handleWebSocketMessage(connectionId: string, message: WsMe
|
|
|
|
|
handleStatusUpdate(user, message, connectionId);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'server_icon_available':
|
|
|
|
|
handleServerIconAvailable(user, message, connectionId);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'server_icon_sync_request':
|
|
|
|
|
handleServerIconSyncRequest(user, message);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case 'plugin_event':
|
|
|
|
|
await handlePluginEvent(user, message);
|
|
|
|
|
break;
|
|
|
|
|
|