package com.xiaopeng.admin.socketio; import com.corundumstudio.socketio.SocketIOClient; import com.corundumstudio.socketio.annotation.OnConnect; import com.corundumstudio.socketio.annotation.OnDisconnect; import com.corundumstudio.socketio.annotation.OnEvent; import com.xiaopeng.api.dto.commandCenter.CommandCenterAuthDto; import com.xiaopeng.api.dto.commandCenter.CommandCenterSubscribeDto; import com.xiaopeng.api.dto.commandCenter.CommandCenterVehicleDetailSubscribeDto; import com.xiaopeng.api.vo.account.LoginUser; import com.xiaopeng.api.vo.commandCenter.CommandCenterVehicleDetailVo; import com.xiaopeng.admin.service.CommandCenterService; import com.xiaopeng.common.security.auth.AuthUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * 指挥中心 Socket.IO 事件处理 * * @ClassName CommandCenterSocketHandler */ @Slf4j @Component public class CommandCenterSocketHandler { private static final String PERMISSION_VIEW = "commandCenter:view"; private static final String CITY_ROOM_PREFIX = "city_"; private static final String FENCE_ROOM_PREFIX = "fence_"; @Resource private SocketIOSessionManager sessionManager; @Resource private CommandCenterService commandCenterService; /** * 客户端连接 * * @param client Socket 客户端 */ @OnConnect public void onConnect(SocketIOClient client) { sessionManager.register(client); log.debug("commandCenter client connected: {}", client.getSessionId()); } /** * 鉴权 * * @param client Socket 客户端 * @param authDto 鉴权参数 */ @OnEvent("auth") public void onAuth(SocketIOClient client, CommandCenterAuthDto authDto) { if (authDto == null || authDto.getToken() == null) { client.sendEvent("auth_failed", Collections.singletonMap("message", "token 不能为空")); client.disconnect(); return; } // 指挥中心服务于管理后台 PC 端(user_type=system), // 走 LoginUser 链路;RBAC 权限点实际写在 sys_menu.router_name, // 对应 LoginUser.roleRouterName(见 AuthLogic#getRouterNameLimit)。 LoginUser user = AuthUtil.getLoginUser(authDto.getToken()); if (user == null) { client.sendEvent("auth_failed", Collections.singletonMap("message", "token 已过期或无效")); client.disconnect(); return; } Set perms = user.getRoleRouterName(); if (perms == null || !perms.contains(PERMISSION_VIEW)) { client.sendEvent("auth_failed", Collections.singletonMap("message", "无权限")); client.disconnect(); return; } client.set("userId", user.getUsername()); client.set("authenticated", true); Map payload = new HashMap<>(); payload.put("userId", user.getUsername()); client.sendEvent("auth_success", payload); } /** * 订阅城市/围栏 * * @param client Socket 客户端 * @param subscribeDto 订阅参数 */ @OnEvent("subscribe") public void onSubscribe(SocketIOClient client, CommandCenterSubscribeDto subscribeDto) { if (!Boolean.TRUE.equals(client.get("authenticated"))) { client.sendEvent("auth_failed", Collections.singletonMap("message", "请先鉴权")); return; } if (subscribeDto == null || subscribeDto.getCityCode() == null) { return; } client.joinRoom(CITY_ROOM_PREFIX + subscribeDto.getCityCode()); if (subscribeDto.getElectronicId() != null) { client.joinRoom(FENCE_ROOM_PREFIX + subscribeDto.getElectronicId()); } sessionManager.trackSubscription(client, subscribeDto.getCityCode()); } /** * 取消订阅 * * @param client Socket 客户端 * @param subscribeDto 订阅参数 */ @OnEvent("unsubscribe") public void onUnsubscribe(SocketIOClient client, CommandCenterSubscribeDto subscribeDto) { if (subscribeDto == null || subscribeDto.getCityCode() == null) { return; } client.leaveRoom(CITY_ROOM_PREFIX + subscribeDto.getCityCode()); if (subscribeDto.getElectronicId() != null) { client.leaveRoom(FENCE_ROOM_PREFIX + subscribeDto.getElectronicId()); } sessionManager.untrackSubscription(client, subscribeDto.getCityCode()); } /** * 订阅单车详情推送(打开详情面板) * * @param client Socket 客户端 * @param dto 订阅参数 */ @OnEvent("subscribe_vehicle_detail") public void onSubscribeVehicleDetail(SocketIOClient client, CommandCenterVehicleDetailSubscribeDto dto) { if (!Boolean.TRUE.equals(client.get("authenticated"))) { client.sendEvent("auth_failed", Collections.singletonMap("message", "请先鉴权")); return; } if (dto == null || dto.getVehicleId() == null) { return; } sessionManager.subscribeVehicleDetail(client, dto.getVehicleId()); CommandCenterVehicleDetailVo detail = commandCenterService.getVehicleDetailForPush(dto.getVehicleId()); if (detail != null) { client.sendEvent("vehicle_detail", detail); } else { log.warn("[CommandCenter] subscribe_vehicle_detail no data vehicleId={}", dto.getVehicleId()); } } /** * 取消单车详情推送(关闭详情面板) * * @param client Socket 客户端 * @param dto 订阅参数(vehicleId 可选) */ @OnEvent("unsubscribe_vehicle_detail") public void onUnsubscribeVehicleDetail(SocketIOClient client, CommandCenterVehicleDetailSubscribeDto dto) { sessionManager.unsubscribeVehicleDetail(client); } /** * 客户端断开 * * @param client Socket 客户端 */ @OnDisconnect public void onDisconnect(SocketIOClient client) { sessionManager.unregister(client); log.debug("commandCenter client disconnected: {}", client.getSessionId()); } }