mirror of
https://github.com/ZeroCatDev/ClassworksKV.git
synced 2025-12-07 21:13:10 +00:00
feat: 更新Socket.IO初始化配置,优化CORS设置和传输方式
This commit is contained in:
parent
e73ff53f58
commit
1e1b99a070
@ -12,9 +12,9 @@
|
|||||||
* - 令牌信息缓存:在连接时预加载令牌详细信息以提高性能
|
* - 令牌信息缓存:在连接时预加载令牌详细信息以提高性能
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {Server} from "socket.io";
|
import { Server } from "socket.io";
|
||||||
import {PrismaClient} from "@prisma/client";
|
import { PrismaClient } from "@prisma/client";
|
||||||
import {onlineDevicesGauge} from "./metrics.js";
|
import { onlineDevicesGauge } from "./metrics.js";
|
||||||
import DeviceDetector from "node-device-detector";
|
import DeviceDetector from "node-device-detector";
|
||||||
import ClientHints from "node-device-detector/client-hints.js";
|
import ClientHints from "node-device-detector/client-hints.js";
|
||||||
|
|
||||||
@ -96,14 +96,16 @@ function detectDeviceName(userAgent, headers = {}) {
|
|||||||
export function initSocket(server) {
|
export function initSocket(server) {
|
||||||
if (io) return io;
|
if (io) return io;
|
||||||
|
|
||||||
const allowOrigin = process.env.FRONTEND_URL || "*";
|
|
||||||
|
|
||||||
io = new Server(server, {
|
io = new Server(server, {
|
||||||
cors: {
|
cors: {
|
||||||
origin: allowOrigin,
|
origin: "*",
|
||||||
methods: ["GET", "POST"],
|
methods: ["GET", "POST"],
|
||||||
credentials: true,
|
allowedHeaders: ["*"],
|
||||||
|
credentials: false
|
||||||
},
|
},
|
||||||
|
// 传输方式回退策略:优先使用WebSocket,回退到轮询
|
||||||
|
transports: ["polling", "websocket"],
|
||||||
});
|
});
|
||||||
|
|
||||||
io.on("connection", (socket) => {
|
io.on("connection", (socket) => {
|
||||||
@ -132,8 +134,8 @@ export function initSocket(server) {
|
|||||||
const token = payload?.token || payload?.apptoken;
|
const token = payload?.token || payload?.apptoken;
|
||||||
if (typeof token !== "string" || token.length === 0) return;
|
if (typeof token !== "string" || token.length === 0) return;
|
||||||
const appInstall = await prisma.appInstall.findUnique({
|
const appInstall = await prisma.appInstall.findUnique({
|
||||||
where: {token},
|
where: { token },
|
||||||
include: {device: {select: {uuid: true}}},
|
include: { device: { select: { uuid: true } } },
|
||||||
});
|
});
|
||||||
const uuid = appInstall?.device?.uuid;
|
const uuid = appInstall?.device?.uuid;
|
||||||
if (uuid) {
|
if (uuid) {
|
||||||
@ -156,11 +158,11 @@ export function initSocket(server) {
|
|||||||
// 获取事件历史记录
|
// 获取事件历史记录
|
||||||
socket.on("get-event-history", (data) => {
|
socket.on("get-event-history", (data) => {
|
||||||
try {
|
try {
|
||||||
const {limit = 50, offset = 0} = data || {};
|
const { limit = 50, offset = 0 } = data || {};
|
||||||
const uuids = Array.from(socket.data.deviceUuids || []);
|
const uuids = Array.from(socket.data.deviceUuids || []);
|
||||||
|
|
||||||
if (uuids.length === 0) {
|
if (uuids.length === 0) {
|
||||||
socket.emit("event-history-error", {reason: "not_joined_any_device"});
|
socket.emit("event-history-error", { reason: "not_joined_any_device" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,7 +184,7 @@ export function initSocket(server) {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("get-event-history error:", err);
|
console.error("get-event-history error:", err);
|
||||||
socket.emit("event-history-error", {reason: "internal_error"});
|
socket.emit("event-history-error", { reason: "internal_error" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -191,35 +193,35 @@ export function initSocket(server) {
|
|||||||
try {
|
try {
|
||||||
// 验证数据结构
|
// 验证数据结构
|
||||||
if (!data || typeof data !== "object") {
|
if (!data || typeof data !== "object") {
|
||||||
socket.emit("event-error", {reason: "invalid_data_format"});
|
socket.emit("event-error", { reason: "invalid_data_format" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const {type, content} = data;
|
const { type, content } = data;
|
||||||
|
|
||||||
// 验证事件类型
|
// 验证事件类型
|
||||||
if (typeof type !== "string" || type.trim().length === 0) {
|
if (typeof type !== "string" || type.trim().length === 0) {
|
||||||
socket.emit("event-error", {reason: "invalid_event_type"});
|
socket.emit("event-error", { reason: "invalid_event_type" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证内容格式(必须是对象或null)
|
// 验证内容格式(必须是对象或null)
|
||||||
if (content !== null && (typeof content !== "object" || Array.isArray(content))) {
|
if (content !== null && (typeof content !== "object" || Array.isArray(content))) {
|
||||||
socket.emit("event-error", {reason: "content_must_be_object_or_null"});
|
socket.emit("event-error", { reason: "content_must_be_object_or_null" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取当前socket所在的设备房间
|
// 获取当前socket所在的设备房间
|
||||||
const uuids = Array.from(socket.data.deviceUuids || []);
|
const uuids = Array.from(socket.data.deviceUuids || []);
|
||||||
if (uuids.length === 0) {
|
if (uuids.length === 0) {
|
||||||
socket.emit("event-error", {reason: "not_joined_any_device"});
|
socket.emit("event-error", { reason: "not_joined_any_device" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查只读权限
|
// 检查只读权限
|
||||||
const tokenInfo = socket.data.tokenInfo;
|
const tokenInfo = socket.data.tokenInfo;
|
||||||
if (tokenInfo?.isReadOnly) {
|
if (tokenInfo?.isReadOnly) {
|
||||||
socket.emit("event-error", {reason: "readonly_token_cannot_send_events"});
|
socket.emit("event-error", { reason: "readonly_token_cannot_send_events" });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,7 +229,7 @@ export function initSocket(server) {
|
|||||||
const MAX_SIZE = 10240; // 10KB
|
const MAX_SIZE = 10240; // 10KB
|
||||||
const serializedContent = JSON.stringify(content);
|
const serializedContent = JSON.stringify(content);
|
||||||
if (serializedContent.length > MAX_SIZE) {
|
if (serializedContent.length > MAX_SIZE) {
|
||||||
socket.emit("event-error", {reason: "content_too_large", maxSize: MAX_SIZE});
|
socket.emit("event-error", { reason: "content_too_large", maxSize: MAX_SIZE });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +276,7 @@ export function initSocket(server) {
|
|||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("send-event error:", err);
|
console.error("send-event error:", err);
|
||||||
socket.emit("event-error", {reason: "internal_error"});
|
socket.emit("event-error", { reason: "internal_error" });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -288,10 +290,10 @@ export function initSocket(server) {
|
|||||||
|
|
||||||
// 清理socket相关缓存
|
// 清理socket相关缓存
|
||||||
if (socket.data.currentToken) {
|
if (socket.data.currentToken) {
|
||||||
// 如果这是该token的最后一个连接,考虑清理缓存
|
// 如果这是该token的最后一个连接,考虑清理缓存
|
||||||
const tokenSet = onlineTokens.get(socket.data.currentToken);
|
const tokenSet = onlineTokens.get(socket.data.currentToken);
|
||||||
if (!tokenSet || tokenSet.size === 0) {
|
if (!tokenSet || tokenSet.size === 0) {
|
||||||
// 可以选择保留缓存一段时间,这里暂时保留
|
// 可以选择保留缓存一段时间,这里暂时保留
|
||||||
// tokenInfoCache.delete(socket.data.currentToken);
|
// tokenInfoCache.delete(socket.data.currentToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,7 +322,7 @@ function joinDeviceRoom(socket, uuid) {
|
|||||||
set.add(socket.id);
|
set.add(socket.id);
|
||||||
onlineMap.set(uuid, set);
|
onlineMap.set(uuid, set);
|
||||||
// 可选:通知加入
|
// 可选:通知加入
|
||||||
io.to(uuid).emit("device-joined", {uuid, connections: set.size});
|
io.to(uuid).emit("device-joined", { uuid, connections: set.size });
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -525,7 +527,7 @@ function cleanupDeviceCache(uuid) {
|
|||||||
export function getOnlineDevices() {
|
export function getOnlineDevices() {
|
||||||
const list = [];
|
const list = [];
|
||||||
for (const [token, set] of onlineTokens.entries()) {
|
for (const [token, set] of onlineTokens.entries()) {
|
||||||
list.push({token, connections: set.size});
|
list.push({ token, connections: set.size });
|
||||||
}
|
}
|
||||||
// 默认按连接数降序
|
// 默认按连接数降序
|
||||||
return list.sort((a, b) => b.connections - a.connections);
|
return list.sort((a, b) => b.connections - a.connections);
|
||||||
@ -549,7 +551,7 @@ export default {
|
|||||||
async function joinByToken(socket, token) {
|
async function joinByToken(socket, token) {
|
||||||
try {
|
try {
|
||||||
const appInstall = await prisma.appInstall.findUnique({
|
const appInstall = await prisma.appInstall.findUnique({
|
||||||
where: {token},
|
where: { token },
|
||||||
include: {
|
include: {
|
||||||
device: {
|
device: {
|
||||||
select: {
|
select: {
|
||||||
@ -606,10 +608,10 @@ async function joinByToken(socket, token) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
socket.emit("join-error", {by: "token", reason: "invalid_token"});
|
socket.emit("join-error", { by: "token", reason: "invalid_token" });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("joinByToken error:", error);
|
console.error("joinByToken error:", error);
|
||||||
socket.emit("join-error", {by: "token", reason: "database_error"});
|
socket.emit("join-error", { by: "token", reason: "database_error" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user