update ip限制改为,同一ip可多个登录用户连接,游客只能存在一个。新增一个因为服务器宕机原因未删除游客聊天室和消息的定时任务

This commit is contained in:
yyb 2025-05-30 17:35:37 +08:00
parent 9904fbeb24
commit ffff88bacf
7 changed files with 93 additions and 27 deletions

View File

@ -5,6 +5,7 @@ import com.m2pool.chat.coverter.CommonMessageConvert;
import com.m2pool.chat.interceptor.WebsocketChannelInterceptor; import com.m2pool.chat.interceptor.WebsocketChannelInterceptor;
import com.m2pool.chat.interceptor.WebsocketHandshakeInterceptor; import com.m2pool.chat.interceptor.WebsocketHandshakeInterceptor;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MessageConverter; import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.simp.config.ChannelRegistration; import org.springframework.messaging.simp.config.ChannelRegistration;
@ -14,6 +15,8 @@ import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBr
import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration;
import org.springframework.web.socket.messaging.StompSubProtocolHandler;
import org.springframework.web.socket.messaging.SubProtocolWebSocketHandler;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.List; import java.util.List;
@ -125,4 +128,5 @@ public class WebSocketBrokerConfig implements WebSocketMessageBrokerConfigurer {
return true; return true;
} }
} }

View File

@ -10,7 +10,7 @@ import lombok.Getter;
*/ */
@Getter @Getter
public enum ExceptionEnum { public enum ExceptionEnum {
IP_LIMIT_CONNECT(1020, "本机连接数已达上限,请关闭已有链接"), IP_LIMIT_CONNECT(1020, "本机连接数已达上限,请关闭已有链接"),
MAX_LIMIT_CONNECT(1021, "服务器websocket连接数已达上限,服务器拒绝链接"), MAX_LIMIT_CONNECT(1021, "服务器websocket连接数已达上限,服务器拒绝链接"),
SET_PRINCIPAL_FAIL(1022, "websocket链接异常,用户身份设置失败"), SET_PRINCIPAL_FAIL(1022, "websocket链接异常,用户身份设置失败"),
GET_PRINCIPAL_FAIL(1023, "websocket链接异常,用户信息邮箱获取失败"), GET_PRINCIPAL_FAIL(1023, "websocket链接异常,用户信息邮箱获取失败"),

View File

@ -4,6 +4,8 @@ package com.m2pool.chat.interceptor;
import com.m2pool.chat.config.CustomWebSocketConfig; import com.m2pool.chat.config.CustomWebSocketConfig;
import com.m2pool.chat.constant.ExceptionEnum; import com.m2pool.chat.constant.ExceptionEnum;
import com.m2pool.chat.entity.StompPrincipal; import com.m2pool.chat.entity.StompPrincipal;
import com.m2pool.chat.listener.IpLimitEvent;
import io.lettuce.core.ScriptOutputType;
import lombok.Data; import lombok.Data;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -39,9 +41,9 @@ public class WebsocketChannelInterceptor implements ChannelInterceptor {
private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketChannelInterceptor.class); private static final Logger LOGGER = LoggerFactory.getLogger(WebsocketChannelInterceptor.class);
/** /**
* 当前加入链接的ip ,key ip ,VALUE 为用户邮箱 * 当前加入链接的ip ,key ip ,VALUE 邮箱
*/ */
private static final ConcurrentHashMap<String,String> ipConnectionCountMap = new ConcurrentHashMap<>(); private static final ConcurrentHashMap<String,EmailLimit> ipConnectionCountMap = new ConcurrentHashMap<>();
/** /**
* 当前链接数 * 当前链接数
@ -121,26 +123,30 @@ public class WebsocketChannelInterceptor implements ChannelInterceptor {
Map<String, Object> sessionAttributes = accessor.getSessionAttributes(); Map<String, Object> sessionAttributes = accessor.getSessionAttributes();
if (sessionAttributes != null) { if (sessionAttributes != null) {
String ipAddr = (String) sessionAttributes.get(IPADDR); String ipAddr = (String) sessionAttributes.get(IPADDR);
String hasConnectionEmail = ipConnectionCountMap.get(ipAddr); EmailLimit emailAndCount = ipConnectionCountMap.get(ipAddr);
//两种ip限制情况 //两种ip限制情况
//本次链接为游客 且ip上已经有人链接直接拒绝本次链接 //本次链接为游客 且ip上已经有人链接直接拒绝本次链接
if(type == TOURIST && hasConnectionEmail != null){ if(type == TOURIST && emailAndCount != null){
throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.IP_LIMIT_CONNECT)); throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.IP_LIMIT_CONNECT));
} }
//本次链接为登录用户,并且已经链接.直接拒绝本次链接(多用户登录)
if ( type == LOGIN_USER ) { //本次链接为登录用户,并且已经链接.直接拒绝本次链接
if(email.equals(hasConnectionEmail) ){ if ( type != TOURIST && emailAndCount != null) {
// StompPrincipal principal = new StompPrincipal(email, type, true); emailAndCount.setCount(emailAndCount.getCount() + 1);
// applicationEventPublisher.publishEvent(new IpLimitEvent(this, principal)); if(email.equals(emailAndCount.getEmail())){
throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.IP_LIMIT_CONNECT)); throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.IP_LIMIT_CONNECT));
} }
if(ipConnectionCountMap.containsValue(email)){ //if(ipConnectionCountMap.containsValue(emailAndCount)){
throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.ACCOUNT_HAS_CONNECTED)); // ipConnectionCountMap.put(ipAddr, emailAndCount);
} // throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.ACCOUNT_HAS_CONNECTED));
//}
}else{
EmailLimit emailLimit = new EmailLimit();
emailLimit.setEmail(email);
emailLimit.setCount(1);
ipConnectionCountMap.put(ipAddr,emailLimit );
} }
ipConnectionCountMap.put(ipAddr,email);
}else{ }else{
throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.GET_PRINCIPAL_FAIL)); throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.GET_PRINCIPAL_FAIL));
} }
@ -156,9 +162,15 @@ public class WebsocketChannelInterceptor implements ChannelInterceptor {
connectionCount.decrementAndGet(); connectionCount.decrementAndGet();
//断开链接的ip //断开链接的ip
Map<String, Object> sessionAttributes = accessor.getSessionAttributes(); Map<String, Object> sessionAttributes = accessor.getSessionAttributes();
if (sessionAttributes != null) { if (sessionAttributes != null ) {
String ipAddr = (String) sessionAttributes.get(IPADDR); String ipAddr = (String) sessionAttributes.get(IPADDR);
ipConnectionCountMap.remove(ipAddr); EmailLimit emailAndCount = ipConnectionCountMap.get(ipAddr);
if (emailAndCount.getCount() > 1){
emailAndCount.setCount(emailAndCount.getCount() - 1);
}else{
ipConnectionCountMap.remove(ipAddr);
}
}else{ }else{
throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.GET_PRINCIPAL_FAIL)); throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.GET_PRINCIPAL_FAIL));
} }
@ -186,4 +198,13 @@ public class WebsocketChannelInterceptor implements ChannelInterceptor {
@Override @Override
public void afterReceiveCompletion(@Nullable Message<?> message, MessageChannel channel, @Nullable Exception ex) { public void afterReceiveCompletion(@Nullable Message<?> message, MessageChannel channel, @Nullable Exception ex) {
} }
/**
* ip限制存储对象
*/
@Data
private class EmailLimit{
private String email;
private int count = 1;
}
} }

View File

@ -1,8 +1,10 @@
package com.m2pool.chat.listener; package com.m2pool.chat.listener;
import com.m2pool.chat.constant.ExceptionEnum;
import com.m2pool.chat.entity.StompPrincipal; import com.m2pool.chat.entity.StompPrincipal;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.messaging.MessageDeliveryException;
import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -18,5 +20,9 @@ public class IpLimitListener implements ApplicationListener<IpLimitEvent> {
// messagingTemplate.convertAndSendToUser(principal.getName(), // messagingTemplate.convertAndSendToUser(principal.getName(),
// Destination.QUEUE + "/" + principal.getName() // Destination.QUEUE + "/" + principal.getName()
// , "ip链接数限制"); // , "ip链接数限制");
throw new MessageDeliveryException(ExceptionEnum.fromCode(ExceptionEnum.IP_LIMIT_CONNECT));
} }
} }

View File

@ -64,6 +64,7 @@ public class StompServiceImpl implements StompService {
ChatRoom chatRoom = chatRoomMapper.selectOne(new LambdaQueryWrapper<ChatRoom>() ChatRoom chatRoom = chatRoomMapper.selectOne(new LambdaQueryWrapper<ChatRoom>()
.eq(ChatRoom::getUserOneEmail, principal.getName()) .eq(ChatRoom::getUserOneEmail, principal.getName())
.eq(ChatRoom::getUserTwoEmail, userMessageVo.getEmail())); .eq(ChatRoom::getUserTwoEmail, userMessageVo.getEmail()));
System.out.println("发送消息聊天室id"+userMessageVo.getRoomId()+"发送者邮箱"+principal.getName()+"接受者邮箱"+userMessageVo.getEmail());
build.setRoomId(String.valueOf(userMessageVo.getRoomId())); build.setRoomId(String.valueOf(userMessageVo.getRoomId()));
int serviceReadNum = chatRoom != null ? chatRoom.getClientReadNum() : 0; int serviceReadNum = chatRoom != null ? chatRoom.getClientReadNum() : 0;
build.setClientReadNum( serviceReadNum+ 1); build.setClientReadNum( serviceReadNum+ 1);
@ -90,6 +91,7 @@ public class StompServiceImpl implements StompService {
.eq(ChatRoom::getUserOneEmail, userMessageVo.getEmail()) .eq(ChatRoom::getUserOneEmail, userMessageVo.getEmail())
.eq(ChatRoom::getUserTwoEmail, principal.getName())); .eq(ChatRoom::getUserTwoEmail, principal.getName()));
build.setRoomId(String.valueOf(userMessageVo.getRoomId())); build.setRoomId(String.valueOf(userMessageVo.getRoomId()));
System.out.println("发送消息聊天室id"+userMessageVo.getRoomId()+"发送者邮箱"+principal.getName()+"接受者邮箱"+userMessageVo.getEmail());
int serviceReadNum = chatRoom != null ? chatRoom.getServiceReadNum() : 0; int serviceReadNum = chatRoom != null ? chatRoom.getServiceReadNum() : 0;
build.setClientReadNum(serviceReadNum + 1); build.setClientReadNum(serviceReadNum + 1);

View File

@ -1,11 +1,15 @@
package com.m2pool.chat.task; package com.m2pool.chat.task;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.m2pool.chat.entity.ChatMessage; import com.m2pool.chat.entity.ChatMessage;
import com.m2pool.chat.entity.ChatMessageHistory; import com.m2pool.chat.entity.ChatMessageHistory;
import com.m2pool.chat.entity.ChatRoom;
import com.m2pool.chat.mapper.ChatMessageMapper; import com.m2pool.chat.mapper.ChatMessageMapper;
import com.m2pool.chat.mapper.ChatRoomMapper;
import com.m2pool.chat.service.ChatMessageHistoryService; import com.m2pool.chat.service.ChatMessageHistoryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.scheduling.annotation.Scheduled;
@ -30,6 +34,8 @@ public class ChatTask {
@Resource @Resource
private ChatMessageHistoryService chatMessageHistoryService; private ChatMessageHistoryService chatMessageHistoryService;
@Autowired
private ChatRoomMapper chatRoomMapper;
// @Scheduled(cron = "0 0/1 * * * ?") // @Scheduled(cron = "0 0/1 * * * ?")
@Scheduled(cron = "0 15 1 * * ?") @Scheduled(cron = "0 15 1 * * ?")
@ -68,4 +74,16 @@ public class ChatTask {
pageNum++; pageNum++;
} while (!chatMessages.isEmpty()); } while (!chatMessages.isEmpty());
} }
/**
* 清理掉因服务器异常未发送到客服这边删除的游客聊天室和消息表数据
*
*/
@Scheduled(cron = "0 16 1 * * ?")
//@Scheduled(cron = "0 0/1 * * * ?")
public void clearTouristDatas(){
chatMessageMapper.delete(new LambdaUpdateWrapper<ChatMessage>()
.like(ChatMessage::getSendEmail, "guest_"));
chatRoomMapper.delete(new LambdaUpdateWrapper<ChatRoom>().like(ChatRoom::getUserOneEmail, "guest_"));
}
} }

View File

@ -1,5 +1,10 @@
package com.m2pool.pool.utils; package com.m2pool.pool.utils;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import java.io.IOException; import java.io.IOException;
import java.net.Socket; import java.net.Socket;
import java.net.UnknownHostException; import java.net.UnknownHostException;
@ -12,13 +17,23 @@ import java.net.UnknownHostException;
public class SocketDemo { public class SocketDemo {
public static void main(String[] args) { public static void main(String[] args) {
try { //try {
//Socket socket = new Socket("10.168.2.167",21233); // //Socket socket = new Socket("10.168.2.167",21233);
Socket socket = new Socket("10.168.2.167",12973); // Socket socket = new Socket("10.168.2.167",12973);
}catch (UnknownHostException e){ //}catch (UnknownHostException e){
System.out.println("无法找到主机: "+e.getMessage()); // System.out.println("无法找到主机: "+e.getMessage());
} catch (IOException e) { //} catch (IOException e) {
System.out.println("连接失败: " + e.getMessage()); // System.out.println("连接失败: " + e.getMessage());
} //}
String url = "http://10.168.2.167:12973/blockflow/chain-info?fromGroup=0&toGroup=0";
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type","application/json");
headers.add("User-Agent", "Mozilla/5.0");
headers.add("apikey","0x09e220e226f2feb7a971a2b6f958e7d4b1c187c8");
HttpEntity<String> httpEntity = new HttpEntity<String>(null, headers);
String s = HttpUtil.get(url);
JSONObject jsonObject = JSONObject.parseObject(s);
int currentHeight = jsonObject.getIntValue("currentHeight");
} }
} }