feat: v1.2.0 房间详情/聊天/踢人 + 速率限制 + WebSocket增强
Server: - API速率限制中间件 (120 req/min per IP, X-RateLimit headers) - 房间聊天API: POST /rooms/:id/chat - 认证中间件放行公开GET路由和房间join - WebSocket: 房间订阅/取消订阅 (subscribe/unsubscribe) - WebSocket: 房间聊天广播 (chat -> broadcastToRoom) - WebSocket: 房间事件通知 (roomCreated/Deleted/playerJoined/Left) Client: - 房间详情弹窗: 点击房间卡片打开 - 房间信息网格 (房间号/房主/版本/人数) - 在线玩家列表 (5秒自动刷新) - 踢出玩家 (确认对话框) - 房间聊天 (实时发送/显示) - 加入房间 / 删除房间按钮 - 连接状态指示器动画 (online/offline/connecting) - 房间卡片hover效果 - 版本更新到 v1.2.0 - ApiClient: 新增 getRoomDetail/kickPlayer/sendChat - Preload: 新增对应IPC方法 - Main: 新增 rooms:detail/kick/chat handlers
This commit is contained in:
@@ -57,4 +57,19 @@ export class ApiClient {
|
||||
const res = await this.http.get('/traffic');
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async getRoomDetail(roomId: string) {
|
||||
const res = await this.http.get(`/rooms/${roomId}`);
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async kickPlayer(roomId: string, playerId: string, reason?: string) {
|
||||
const res = await this.http.post(`/rooms/${roomId}/kick/${playerId}`, { reason });
|
||||
return res.data;
|
||||
}
|
||||
|
||||
async sendChat(roomId: string, sender: string, message: string) {
|
||||
const res = await this.http.post(`/rooms/${roomId}/chat`, { sender, message });
|
||||
return res.data;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,3 +245,36 @@ ipcMain.handle('rooms:verify', async (_event, opts: { roomId: string; password?:
|
||||
return { success: false, error: err.response?.data?.error || err.message };
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Room detail (players list) =====
|
||||
ipcMain.handle('rooms:detail', async (_event, roomId: string) => {
|
||||
if (!apiClient) return { success: false, error: '未连接服务器' };
|
||||
try {
|
||||
const data = await apiClient.getRoomDetail(roomId);
|
||||
return { success: true, data };
|
||||
} catch (err: any) {
|
||||
return { success: false, error: err.response?.data?.error || err.message };
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Kick player =====
|
||||
ipcMain.handle('rooms:kick', async (_event, roomId: string, playerId: string) => {
|
||||
if (!apiClient) return { success: false, error: '未连接服务器' };
|
||||
try {
|
||||
const data = await apiClient.kickPlayer(roomId, playerId);
|
||||
return { success: true, data };
|
||||
} catch (err: any) {
|
||||
return { success: false, error: err.response?.data?.error || err.message };
|
||||
}
|
||||
});
|
||||
|
||||
// ===== Room chat =====
|
||||
ipcMain.handle('rooms:chat', async (_event, roomId: string, sender: string, message: string) => {
|
||||
if (!apiClient) return { success: false, error: '未连接服务器' };
|
||||
try {
|
||||
const data = await apiClient.sendChat(roomId, sender, message);
|
||||
return { success: true, data };
|
||||
} catch (err: any) {
|
||||
return { success: false, error: err.response?.data?.error || err.message };
|
||||
}
|
||||
});
|
||||
|
||||
@@ -18,7 +18,10 @@ contextBridge.exposeInMainWorld('funmc', {
|
||||
hostRoom: (opts: any) => ipcRenderer.invoke('rooms:host', opts),
|
||||
disconnect: () => ipcRenderer.invoke('relay:disconnect'),
|
||||
|
||||
// Room verification
|
||||
// Room detail & actions
|
||||
getRoomDetail: (id: string) => ipcRenderer.invoke('rooms:detail', id),
|
||||
kickPlayer: (roomId: string, playerId: string) => ipcRenderer.invoke('rooms:kick', roomId, playerId),
|
||||
sendChat: (roomId: string, sender: string, message: string) => ipcRenderer.invoke('rooms:chat', roomId, sender, message),
|
||||
verifyRoom: (opts: any) => ipcRenderer.invoke('rooms:verify', opts),
|
||||
|
||||
// Settings
|
||||
|
||||
Reference in New Issue
Block a user