|
|
@@ -0,0 +1,201 @@
|
|
|
+package cn.reghao.tnb.message.app.ws.media;
|
|
|
+
|
|
|
+import cn.reghao.jutil.jdk.serializer.JdkSerializer;
|
|
|
+import cn.reghao.jutil.jdk.serializer.JsonConverter;
|
|
|
+import cn.reghao.tnb.account.api.constant.TokenType;
|
|
|
+import cn.reghao.tnb.account.api.dto.AuthedAccount;
|
|
|
+import cn.reghao.tnb.account.api.iface.AccountQuery;
|
|
|
+import cn.reghao.tnb.message.api.dto.PushMsg;
|
|
|
+import cn.reghao.tnb.message.api.dto.event.EventMsg;
|
|
|
+import cn.reghao.tnb.message.api.model.EventType;
|
|
|
+import cn.reghao.tnb.message.api.model.resp.EventMessageResp;
|
|
|
+import cn.reghao.tnb.message.app.rabbit.RabbitProducer;
|
|
|
+import cn.reghao.tnb.message.app.redis.RedisKeys;
|
|
|
+import cn.reghao.tnb.message.app.redis.ds.RedisHash;
|
|
|
+import cn.reghao.tnb.message.app.redis.ds.RedisString;
|
|
|
+import cn.reghao.tnb.message.app.ws.chat.msg.ChatPayload;
|
|
|
+import cn.reghao.tnb.message.app.ws.chat.msg.EventResp;
|
|
|
+import cn.reghao.tnb.message.app.ws.config.PingPayload;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.dubbo.config.annotation.DubboReference;
|
|
|
+import org.springframework.stereotype.Component;
|
|
|
+import org.springframework.web.socket.BinaryMessage;
|
|
|
+import org.springframework.web.socket.TextMessage;
|
|
|
+import org.springframework.web.socket.WebSocketSession;
|
|
|
+
|
|
|
+import java.io.IOException;
|
|
|
+import java.net.InetSocketAddress;
|
|
|
+import java.util.*;
|
|
|
+
|
|
|
+/**
|
|
|
+ * @author reghao
|
|
|
+ * @date 2022-09-01 10:44:06
|
|
|
+ */
|
|
|
+@Slf4j
|
|
|
+@Component
|
|
|
+public class MediaConnection {
|
|
|
+ @DubboReference(check = false, retries = 0, timeout = 60_000)
|
|
|
+ private AccountQuery accountQuery;
|
|
|
+
|
|
|
+ private final RabbitProducer rabbitProducer;
|
|
|
+ private RedisString redisString;
|
|
|
+ private RedisHash<HashSet<Long>> redisHash;
|
|
|
+ // userId -> session
|
|
|
+ private final Map<Long, WebSocketSession> userSessions = new HashMap<>();
|
|
|
+ // sessionId -> userId
|
|
|
+ private final Map<String, Long> sessionUsers = new HashMap<>();
|
|
|
+
|
|
|
+ public MediaConnection(RabbitProducer rabbitProducer, RedisString redisString, RedisHash<HashSet<Long>> redisHash) {
|
|
|
+ this.rabbitProducer = rabbitProducer;
|
|
|
+ this.redisString = redisString;
|
|
|
+ this.redisHash = redisHash;
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean addSession(WebSocketSession webSocketSession) {
|
|
|
+ String userToken = (String) webSocketSession.getAttributes().get("userToken");
|
|
|
+ String videoId = (String) webSocketSession.getAttributes().get("videoId");
|
|
|
+ AuthedAccount authedAccount = accountQuery.getAuthedAccount(TokenType.token.getValue(), userToken);
|
|
|
+ if (authedAccount != null) {
|
|
|
+ long userId = authedAccount.getUserId();
|
|
|
+ String redisKey = RedisKeys.getVideoUsersKey(videoId);
|
|
|
+ HashSet<Long> userIds = redisHash.get(redisKey, videoId);
|
|
|
+ if (userIds == null) {
|
|
|
+ userIds = new HashSet<>();
|
|
|
+ userIds.add(userId);
|
|
|
+ } else {
|
|
|
+ userIds.add(userId);
|
|
|
+ }
|
|
|
+ redisHash.hset(redisKey, videoId, userIds);
|
|
|
+
|
|
|
+ addUserSession(userId, webSocketSession);
|
|
|
+ sendViewCount(videoId);
|
|
|
+
|
|
|
+ Map<String, Object> wsMessage = new HashMap<>();
|
|
|
+ String serverAddress = System.getenv("SERVER_ADDRESS");
|
|
|
+ wsMessage.put("broadcastBy", serverAddress);
|
|
|
+ wsMessage.put("type", "sendViewCount");
|
|
|
+ wsMessage.put("videoId", videoId);
|
|
|
+ broadcastCluster(JsonConverter.objectToJson(wsMessage));
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ public void addUserSession(long userId, WebSocketSession webSocketSession) {
|
|
|
+ String sessionId = webSocketSession.getId();
|
|
|
+ userSessions.put(userId, webSocketSession);
|
|
|
+ sessionUsers.put(sessionId, userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void removeUserSession(WebSocketSession webSocketSession) {
|
|
|
+ String sessionId = webSocketSession.getId();
|
|
|
+ Long userId = sessionUsers.get(sessionId);
|
|
|
+ userSessions.remove(userId);
|
|
|
+ sessionUsers.remove(userId);
|
|
|
+ }
|
|
|
+
|
|
|
+ public Long getUserId(String sessionId) {
|
|
|
+ return sessionUsers.get(sessionId);
|
|
|
+ }
|
|
|
+
|
|
|
+ public WebSocketSession getUserSession(long userId) {
|
|
|
+ return userSessions.get(userId+"");
|
|
|
+ }
|
|
|
+
|
|
|
+ public void sendPingPayload(WebSocketSession session) throws IOException {
|
|
|
+ PingPayload pingPayload = new PingPayload(60, 120);
|
|
|
+ EventResp eventResp = new EventResp();
|
|
|
+ eventResp.setEvent("connect");
|
|
|
+ eventResp.setPayload(pingPayload);
|
|
|
+
|
|
|
+ TextMessage textMessage = new TextMessage(JsonConverter.objectToJson(eventResp));
|
|
|
+ session.sendMessage(textMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void sendHeartbeatPong(WebSocketSession session) throws IOException {
|
|
|
+ EventMessageResp<String> resp = new EventMessageResp<>(EventType.heartbeat, "pong");
|
|
|
+ TextMessage textMessage = new TextMessage(JsonConverter.objectToJson(resp));
|
|
|
+ session.sendMessage(textMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void sendTextMsg(PushMsg pushMsg) throws IOException {
|
|
|
+ String userId = pushMsg.getReceiverId();
|
|
|
+ EventMsg eventMsg = pushMsg.getEventMsg();
|
|
|
+
|
|
|
+ WebSocketSession webSocketSession = userSessions.get(userId);
|
|
|
+ if (webSocketSession == null) {
|
|
|
+ log.error("{} 不在线", userId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ TextMessage textMessage = new TextMessage(JsonConverter.objectToJson(eventMsg));
|
|
|
+ webSocketSession.sendMessage(textMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void send(String receiverId, String content) throws IOException {
|
|
|
+ WebSocketSession webSocketSession = userSessions.get(receiverId);
|
|
|
+ if (webSocketSession == null) {
|
|
|
+ log.error("{} 不在线", receiverId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ EventMessageResp<String> resp = new EventMessageResp<>(EventType.event_content, content);
|
|
|
+ TextMessage textMessage = new TextMessage(JsonConverter.objectToJson(resp));
|
|
|
+ webSocketSession.sendMessage(textMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void send1(String receiverId, Object object) throws IOException {
|
|
|
+ WebSocketSession webSocketSession = userSessions.get(receiverId);
|
|
|
+ if (webSocketSession == null) {
|
|
|
+ log.error("{} 不在线", receiverId);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ TextMessage textMessage = new TextMessage(JsonConverter.objectToJson(object));
|
|
|
+ webSocketSession.sendMessage(textMessage);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void send(String receiverId, Object message) throws IOException {
|
|
|
+ WebSocketSession session = userSessions.get(receiverId);
|
|
|
+ if (session != null) {
|
|
|
+ byte[] bytes = JdkSerializer.serialize(message);
|
|
|
+ BinaryMessage binaryMessage = new BinaryMessage(bytes);
|
|
|
+ session.sendMessage(binaryMessage);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ public void sendViewCount(String videoId) {
|
|
|
+ String redisKey = RedisKeys.getVideoUsersKey(videoId);
|
|
|
+ Set<Long> userIds = redisHash.get(redisKey, videoId);
|
|
|
+ if (userIds == null) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ int viewCount = userIds.size();
|
|
|
+ Map<String, Object> message = new HashMap<>();
|
|
|
+ message.put("viewCount", viewCount);
|
|
|
+ userIds.forEach(userId -> {
|
|
|
+ WebSocketSession session = userSessions.get(userId);
|
|
|
+ if (session != null) {
|
|
|
+ String json = JsonConverter.objectToJson(message);
|
|
|
+ TextMessage textMessage = new TextMessage(json);
|
|
|
+ try {
|
|
|
+ session.sendMessage(textMessage);
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 集群中广播
|
|
|
+ *
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ * @date 2025-10-11 20:10:127
|
|
|
+ */
|
|
|
+ public void broadcastCluster(String payload) {
|
|
|
+ rabbitProducer.broadcastWsMessage(payload);
|
|
|
+ }
|
|
|
+}
|