Compare commits
9 Commits
cde20c6fd7
...
feature/ch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cd2a197288 | ||
| 01787d701c | |||
| 6e7de1a11a | |||
|
|
d92a078fc7 | ||
| 9785908ca9 | |||
| 592a745b8f | |||
| 299627dac7 | |||
| ae3a256c52 | |||
| 97ea698f38 |
@@ -6,6 +6,7 @@ import { AppController } from './app.controller';
|
|||||||
import { AppService } from './app.service';
|
import { AppService } from './app.service';
|
||||||
import { LoggerModule } from './core/utils/logger/logger.module';
|
import { LoggerModule } from './core/utils/logger/logger.module';
|
||||||
import { UsersModule } from './core/db/users/users.module';
|
import { UsersModule } from './core/db/users/users.module';
|
||||||
|
import { ZulipAccountsModule } from './core/db/zulip_accounts/zulip_accounts.module';
|
||||||
import { LoginCoreModule } from './core/login_core/login_core.module';
|
import { LoginCoreModule } from './core/login_core/login_core.module';
|
||||||
import { AuthGatewayModule } from './gateway/auth/auth.gateway.module';
|
import { AuthGatewayModule } from './gateway/auth/auth.gateway.module';
|
||||||
import { ChatGatewayModule } from './gateway/chat/chat.gateway.module';
|
import { ChatGatewayModule } from './gateway/chat/chat.gateway.module';
|
||||||
@@ -62,6 +63,8 @@ function isDatabaseConfigured(): boolean {
|
|||||||
database: process.env.DB_NAME,
|
database: process.env.DB_NAME,
|
||||||
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
entities: [__dirname + '/**/*.entity{.ts,.js}'],
|
||||||
synchronize: false,
|
synchronize: false,
|
||||||
|
// 字符集配置 - 支持中文和emoji
|
||||||
|
charset: 'utf8mb4',
|
||||||
// 添加连接超时和重试配置
|
// 添加连接超时和重试配置
|
||||||
connectTimeout: 10000,
|
connectTimeout: 10000,
|
||||||
retryAttempts: 3,
|
retryAttempts: 3,
|
||||||
@@ -70,6 +73,8 @@ function isDatabaseConfigured(): boolean {
|
|||||||
] : []),
|
] : []),
|
||||||
// 根据数据库配置选择用户模块模式
|
// 根据数据库配置选择用户模块模式
|
||||||
isDatabaseConfigured() ? UsersModule.forDatabase() : UsersModule.forMemory(),
|
isDatabaseConfigured() ? UsersModule.forDatabase() : UsersModule.forMemory(),
|
||||||
|
// Zulip账号关联模块 - 全局单例,其他模块无需重复导入
|
||||||
|
ZulipAccountsModule.forRoot(),
|
||||||
LoginCoreModule,
|
LoginCoreModule,
|
||||||
AuthGatewayModule, // 认证网关模块
|
AuthGatewayModule, // 认证网关模块
|
||||||
ChatGatewayModule, // 聊天网关模块
|
ChatGatewayModule, // 聊天网关模块
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ import { AdminCoreModule } from '../../core/admin_core/admin_core.module';
|
|||||||
import { LoggerModule } from '../../core/utils/logger/logger.module';
|
import { LoggerModule } from '../../core/utils/logger/logger.module';
|
||||||
import { UsersModule } from '../../core/db/users/users.module';
|
import { UsersModule } from '../../core/db/users/users.module';
|
||||||
import { UserProfilesModule } from '../../core/db/user_profiles/user_profiles.module';
|
import { UserProfilesModule } from '../../core/db/user_profiles/user_profiles.module';
|
||||||
import { ZulipAccountsModule } from '../../core/db/zulip_accounts/zulip_accounts.module';
|
|
||||||
import { AdminController } from './admin.controller';
|
import { AdminController } from './admin.controller';
|
||||||
import { AdminService } from './admin.service';
|
import { AdminService } from './admin.service';
|
||||||
import { AdminDatabaseController } from './admin_database.controller';
|
import { AdminDatabaseController } from './admin_database.controller';
|
||||||
@@ -55,8 +54,7 @@ function isDatabaseConfigured(): boolean {
|
|||||||
UsersModule,
|
UsersModule,
|
||||||
// 根据数据库配置选择UserProfiles模块模式
|
// 根据数据库配置选择UserProfiles模块模式
|
||||||
isDatabaseConfigured() ? UserProfilesModule.forDatabase() : UserProfilesModule.forMemory(),
|
isDatabaseConfigured() ? UserProfilesModule.forDatabase() : UserProfilesModule.forMemory(),
|
||||||
// 根据数据库配置选择ZulipAccounts模块模式
|
// 注意:ZulipAccountsModule 是全局模块,已在 AppModule 中导入,无需重复导入
|
||||||
isDatabaseConfigured() ? ZulipAccountsModule.forDatabase() : ZulipAccountsModule.forMemory(),
|
|
||||||
// 注册AdminOperationLog实体
|
// 注册AdminOperationLog实体
|
||||||
TypeOrmModule.forFeature([AdminOperationLog])
|
TypeOrmModule.forFeature([AdminOperationLog])
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import { LoginService } from './login.service';
|
|||||||
import { RegisterService } from './register.service';
|
import { RegisterService } from './register.service';
|
||||||
import { LoginCoreModule } from '../../core/login_core/login_core.module';
|
import { LoginCoreModule } from '../../core/login_core/login_core.module';
|
||||||
import { ZulipCoreModule } from '../../core/zulip_core/zulip_core.module';
|
import { ZulipCoreModule } from '../../core/zulip_core/zulip_core.module';
|
||||||
import { ZulipAccountsModule } from '../../core/db/zulip_accounts/zulip_accounts.module';
|
|
||||||
import { UsersModule } from '../../core/db/users/users.module';
|
import { UsersModule } from '../../core/db/users/users.module';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
@@ -44,7 +43,7 @@ import { UsersModule } from '../../core/db/users/users.module';
|
|||||||
// 导入核心层模块
|
// 导入核心层模块
|
||||||
LoginCoreModule,
|
LoginCoreModule,
|
||||||
ZulipCoreModule,
|
ZulipCoreModule,
|
||||||
ZulipAccountsModule.forRoot(),
|
// 注意:ZulipAccountsModule 是全局模块,已在 AppModule 中导入,无需重复导入
|
||||||
UsersModule,
|
UsersModule,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
|||||||
@@ -36,7 +36,6 @@ import { ZulipEventProcessorService } from './services/zulip_event_processor.ser
|
|||||||
import { ZulipAccountsBusinessService } from './services/zulip_accounts_business.service';
|
import { ZulipAccountsBusinessService } from './services/zulip_accounts_business.service';
|
||||||
// 依赖模块
|
// 依赖模块
|
||||||
import { ZulipCoreModule } from '../../core/zulip_core/zulip_core.module';
|
import { ZulipCoreModule } from '../../core/zulip_core/zulip_core.module';
|
||||||
import { ZulipAccountsModule } from '../../core/db/zulip_accounts/zulip_accounts.module';
|
|
||||||
import { RedisModule } from '../../core/redis/redis.module';
|
import { RedisModule } from '../../core/redis/redis.module';
|
||||||
import { LoggerModule } from '../../core/utils/logger/logger.module';
|
import { LoggerModule } from '../../core/utils/logger/logger.module';
|
||||||
import { LoginCoreModule } from '../../core/login_core/login_core.module';
|
import { LoginCoreModule } from '../../core/login_core/login_core.module';
|
||||||
@@ -50,8 +49,7 @@ import { ChatModule } from '../chat/chat.module';
|
|||||||
CacheModule.register(),
|
CacheModule.register(),
|
||||||
// Zulip核心服务模块
|
// Zulip核心服务模块
|
||||||
ZulipCoreModule,
|
ZulipCoreModule,
|
||||||
// Zulip账号关联模块
|
// 注意:ZulipAccountsModule 是全局模块,已在 AppModule 中导入,无需重复导入
|
||||||
ZulipAccountsModule.forRoot(),
|
|
||||||
// Redis模块
|
// Redis模块
|
||||||
RedisModule,
|
RedisModule,
|
||||||
// 日志模块
|
// 日志模块
|
||||||
|
|||||||
@@ -169,6 +169,9 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
|
|||||||
case 'position':
|
case 'position':
|
||||||
await this.handlePosition(ws, message);
|
await this.handlePosition(ws, message);
|
||||||
break;
|
break;
|
||||||
|
case 'change_map':
|
||||||
|
await this.handleChangeMap(ws, message);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
this.logger.warn(`未知消息类型: ${messageType}`);
|
this.logger.warn(`未知消息类型: ${messageType}`);
|
||||||
this.sendError(ws, `未知消息类型: ${messageType}`);
|
this.sendError(ws, `未知消息类型: ${messageType}`);
|
||||||
@@ -254,7 +257,7 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
|
|||||||
* 处理聊天消息
|
* 处理聊天消息
|
||||||
*
|
*
|
||||||
* @param ws WebSocket 连接实例
|
* @param ws WebSocket 连接实例
|
||||||
* @param message 聊天消息(包含 content, scope)
|
* @param message 聊天消息(包含 content, scope, mapId)
|
||||||
*/
|
*/
|
||||||
private async handleChat(ws: ExtendedWebSocket, message: any) {
|
private async handleChat(ws: ExtendedWebSocket, message: any) {
|
||||||
if (!ws.authenticated) {
|
if (!ws.authenticated) {
|
||||||
@@ -271,7 +274,8 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
|
|||||||
const result = await this.chatService.sendChatMessage({
|
const result = await this.chatService.sendChatMessage({
|
||||||
socketId: ws.id,
|
socketId: ws.id,
|
||||||
content: message.content,
|
content: message.content,
|
||||||
scope: message.scope || 'local'
|
scope: message.scope || 'local',
|
||||||
|
mapId: message.mapId || ws.currentMap, // 支持指定目标地图
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
@@ -335,6 +339,82 @@ export class ChatWebSocketGateway implements OnModuleInit, OnModuleDestroy, ICha
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理切换地图
|
||||||
|
*
|
||||||
|
* @param ws WebSocket 连接实例
|
||||||
|
* @param message 切换地图消息(包含 mapId)
|
||||||
|
*/
|
||||||
|
private async handleChangeMap(ws: ExtendedWebSocket, message: any) {
|
||||||
|
if (!ws.authenticated) {
|
||||||
|
this.sendError(ws, '请先登录');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!message.mapId) {
|
||||||
|
this.sendError(ws, '地图ID不能为空');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const oldMapId = ws.currentMap;
|
||||||
|
const newMapId = message.mapId;
|
||||||
|
|
||||||
|
// 如果地图相同,直接返回成功
|
||||||
|
if (oldMapId === newMapId) {
|
||||||
|
this.sendMessage(ws, {
|
||||||
|
t: 'map_changed',
|
||||||
|
mapId: newMapId,
|
||||||
|
message: '已在当前地图'
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新房间
|
||||||
|
this.leaveMapRoom(ws.id, oldMapId);
|
||||||
|
this.joinMapRoom(ws.id, newMapId);
|
||||||
|
ws.currentMap = newMapId;
|
||||||
|
|
||||||
|
// 更新会话中的地图信息(使用默认位置)
|
||||||
|
await this.chatService.updatePlayerPosition({
|
||||||
|
socketId: ws.id,
|
||||||
|
x: message.x || 400,
|
||||||
|
y: message.y || 300,
|
||||||
|
mapId: newMapId
|
||||||
|
});
|
||||||
|
|
||||||
|
// 通知客户端切换成功
|
||||||
|
this.sendMessage(ws, {
|
||||||
|
t: 'map_changed',
|
||||||
|
mapId: newMapId,
|
||||||
|
oldMapId: oldMapId,
|
||||||
|
message: '地图切换成功'
|
||||||
|
});
|
||||||
|
|
||||||
|
// 向旧地图广播玩家离开
|
||||||
|
this.broadcastToMap(oldMapId, {
|
||||||
|
t: 'player_left',
|
||||||
|
userId: ws.userId,
|
||||||
|
username: ws.username,
|
||||||
|
mapId: oldMapId
|
||||||
|
});
|
||||||
|
|
||||||
|
// 向新地图广播玩家加入
|
||||||
|
this.broadcastToMap(newMapId, {
|
||||||
|
t: 'player_joined',
|
||||||
|
userId: ws.userId,
|
||||||
|
username: ws.username,
|
||||||
|
mapId: newMapId
|
||||||
|
}, ws.id);
|
||||||
|
|
||||||
|
this.logger.log(`用户切换地图: ${ws.username} (${oldMapId} -> ${newMapId})`);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error('切换地图处理失败', error);
|
||||||
|
this.sendError(ws, '切换地图处理失败');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 处理连接关闭
|
* 处理连接关闭
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user