package com.xiaopeng.admin.socketio;
|
|
import com.corundumstudio.socketio.SocketIOClient;
|
import org.springframework.stereotype.Component;
|
|
import java.util.Collections;
|
import java.util.HashSet;
|
import java.util.Map;
|
import java.util.Set;
|
import java.util.concurrent.ConcurrentHashMap;
|
|
/**
|
* Socket.IO 会话管理
|
*
|
* @ClassName SocketIOSessionManager
|
* @Description 跟踪连接、城市订阅与单车详情订阅
|
*/
|
@Component
|
public class SocketIOSessionManager {
|
|
private final Map<String, SocketIOClient> clients = new ConcurrentHashMap<>();
|
private final Map<String, Set<String>> clientCitySubscriptions = new ConcurrentHashMap<>();
|
private final Map<String, Long> clientVehicleDetailSubscription = new ConcurrentHashMap<>();
|
private final Map<Long, Set<String>> vehicleDetailSubscribers = new ConcurrentHashMap<>();
|
|
/**
|
* 注册客户端
|
*
|
* @param client Socket 客户端
|
*/
|
public void register(SocketIOClient client) {
|
clients.put(client.getSessionId().toString(), client);
|
}
|
|
/**
|
* 注销客户端
|
*
|
* @param client Socket 客户端
|
*/
|
public void unregister(SocketIOClient client) {
|
unsubscribeVehicleDetail(client);
|
clients.remove(client.getSessionId().toString());
|
clientCitySubscriptions.remove(client.getSessionId().toString());
|
}
|
|
/**
|
* 记录城市订阅
|
*
|
* @param client Socket 客户端
|
* @param cityCode 城市编码
|
*/
|
public void trackSubscription(SocketIOClient client, String cityCode) {
|
clientCitySubscriptions
|
.computeIfAbsent(client.getSessionId().toString(), key -> ConcurrentHashMap.newKeySet())
|
.add(cityCode);
|
}
|
|
/**
|
* 移除城市订阅记录
|
*
|
* @param client Socket 客户端
|
* @param cityCode 城市编码
|
*/
|
public void untrackSubscription(SocketIOClient client, String cityCode) {
|
Set<String> cities = clientCitySubscriptions.get(client.getSessionId().toString());
|
if (cities != null) {
|
cities.remove(cityCode);
|
}
|
}
|
|
/**
|
* 订阅单车详情推送(同一客户端仅保留一个 vehicleId)
|
*
|
* @param client Socket 客户端
|
* @param vehicleId 车辆 ID
|
*/
|
public void subscribeVehicleDetail(SocketIOClient client, Long vehicleId) {
|
if (vehicleId == null) {
|
return;
|
}
|
String sessionId = client.getSessionId().toString();
|
Long previous = clientVehicleDetailSubscription.get(sessionId);
|
if (previous != null) {
|
removeVehicleSubscriber(previous, sessionId);
|
}
|
clientVehicleDetailSubscription.put(sessionId, vehicleId);
|
vehicleDetailSubscribers.computeIfAbsent(vehicleId, key -> ConcurrentHashMap.newKeySet()).add(sessionId);
|
}
|
|
/**
|
* 取消单车详情订阅
|
*
|
* @param client Socket 客户端
|
*/
|
public void unsubscribeVehicleDetail(SocketIOClient client) {
|
String sessionId = client.getSessionId().toString();
|
Long vehicleId = clientVehicleDetailSubscription.remove(sessionId);
|
if (vehicleId != null) {
|
removeVehicleSubscriber(vehicleId, sessionId);
|
}
|
}
|
|
/**
|
* 当前被订阅的所有车辆 ID(去重)
|
*
|
* @return 车辆 ID 集合
|
*/
|
public Set<Long> getSubscribedVehicleIds() {
|
return new HashSet<>(vehicleDetailSubscribers.keySet());
|
}
|
|
/**
|
* 订阅指定车辆详情的 sessionId 集合
|
*
|
* @param vehicleId 车辆 ID
|
* @return sessionId 集合
|
*/
|
public Set<String> getSubscriberSessionIds(Long vehicleId) {
|
Set<String> subscribers = vehicleDetailSubscribers.get(vehicleId);
|
return subscribers != null ? new HashSet<>(subscribers) : Collections.emptySet();
|
}
|
|
/**
|
* 按 sessionId 获取客户端
|
*
|
* @param sessionId 会话 ID
|
* @return 客户端,不存在返回 null
|
*/
|
public SocketIOClient getClient(String sessionId) {
|
return clients.get(sessionId);
|
}
|
|
private void removeVehicleSubscriber(Long vehicleId, String sessionId) {
|
vehicleDetailSubscribers.computeIfPresent(vehicleId, (key, subscribers) -> {
|
subscribers.remove(sessionId);
|
return subscribers.isEmpty() ? null : subscribers;
|
});
|
}
|
}
|