feat: move the old chess controller to this branch
This commit is contained in:
parent
374271bd47
commit
73d061979b
@ -28,7 +28,8 @@ repositories {
|
||||
|
||||
dependencies {
|
||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||
implementation("org.mmga:make-minecraft-great-again-spring-boot-starter:0.0.5-20241224.081553-6")
|
||||
implementation("org.springframework.boot:spring-boot-starter-websocket")
|
||||
implementation("org.mmga:make-minecraft-great-again-spring-boot-starter:0.0.5-20241224.092835-8")
|
||||
implementation("com.mybatis-flex:mybatis-flex-spring-boot-starter:1.10.2")
|
||||
annotationProcessor("com.mybatis-flex:mybatis-flex-processor:1.10.2")
|
||||
// https://mvnrepository.com/artifact/commons-codec/commons-codec
|
||||
|
@ -5,8 +5,10 @@ import com.mybatisflex.core.audit.ConsoleMessageCollector;
|
||||
import com.mybatisflex.core.audit.MessageCollector;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
|
||||
@SpringBootApplication
|
||||
@EnableWebSocket
|
||||
public class ClubApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
@ -0,0 +1,13 @@
|
||||
package org.blue.club.configuration;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
|
||||
|
||||
@Configuration
|
||||
public class WebSocketConfiguration {
|
||||
@Bean
|
||||
public ServerEndpointExporter serverEndpointExporter() {
|
||||
return new ServerEndpointExporter();
|
||||
}
|
||||
}
|
275
src/main/java/org/blue/club/controller/ChessController.java
Normal file
275
src/main/java/org/blue/club/controller/ChessController.java
Normal file
@ -0,0 +1,275 @@
|
||||
package org.blue.club.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONException;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.websocket.*;
|
||||
import jakarta.websocket.server.PathParam;
|
||||
import jakarta.websocket.server.ServerEndpoint;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.blue.club.dao.UserDao;
|
||||
import org.blue.club.entities.dto.chess.Room;
|
||||
import org.blue.club.entities.dto.chess.packet.*;
|
||||
import org.blue.club.entities.dto.chess.packet.request.*;
|
||||
import org.blue.club.entities.dto.user.User;
|
||||
import org.blue.club.utils.WebSocketUtils;
|
||||
import org.mmga.spring.boot.starter.componet.JwtUtils;
|
||||
import org.mmga.spring.boot.starter.utils.VoUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
@Slf4j
|
||||
@Tag(name = "五子棋", description = "五子棋相关websocket接口")
|
||||
@ServerEndpoint("/chess/{token}")
|
||||
@Component
|
||||
@NoArgsConstructor
|
||||
public class ChessController {
|
||||
private static final ConcurrentHashMap<String, Session> sessions = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, User> users = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<UUID, Room> rooms = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<Session, Boolean> pingPong = new ConcurrentHashMap<>();
|
||||
private static JwtUtils jwtUtils;
|
||||
private static VoUtils voUtils;
|
||||
private static UserDao userDao;
|
||||
|
||||
@Autowired
|
||||
public void setVoUtils(VoUtils voUtils) {
|
||||
ChessController.voUtils = voUtils;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setUserDao(UserDao userDao) {
|
||||
ChessController.userDao = userDao;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
public void setJwtUtils(JwtUtils jwtUtils) {
|
||||
ChessController.jwtUtils = jwtUtils;
|
||||
}
|
||||
|
||||
private final Queue<String> messageQueue = new ConcurrentLinkedQueue<>();
|
||||
private boolean isLogin = false;
|
||||
|
||||
@SneakyThrows
|
||||
@OnOpen
|
||||
public void onOpen(Session session, @PathParam("token") String token) {
|
||||
isLogin = false;
|
||||
Optional<Long> i = jwtUtils.verifyToken(token);
|
||||
if (i.isEmpty()) {
|
||||
WebSocketUtils.sendPacket(new ErrorPacket("token验证失败!"), session);
|
||||
log.info("closed by token verifier");
|
||||
session.close(new CloseReason(CloseReason.CloseCodes.CANNOT_ACCEPT, "token验证失败!"));
|
||||
messageQueue.clear();
|
||||
return;
|
||||
}
|
||||
String sessionId = session.getId();
|
||||
User user = voUtils.vo2DtoSafe(userDao.selectOneWithRelationsById(i.get()), User.class);
|
||||
WebSocketUtils.sendPacket(new UserInfoPacket(user), session);
|
||||
String existsUser = null;
|
||||
long id = user.getId();
|
||||
for (Map.Entry<String, User> entry : users.entrySet()) {
|
||||
User value = entry.getValue();
|
||||
if (value.getId() == id) {
|
||||
existsUser = entry.getKey();
|
||||
break;
|
||||
}
|
||||
}
|
||||
users.put(sessionId, user);
|
||||
sessions.put(sessionId, session);
|
||||
isLogin = true;
|
||||
if (existsUser != null) {
|
||||
users.remove(existsUser);
|
||||
Room roomByPlayer = getRoomByPlayer(existsUser);
|
||||
if (roomByPlayer != null) {
|
||||
roomByPlayer.replace(existsUser, session);
|
||||
WebSocketUtils.sendPacket(new PlayerSideAllocationPacket(roomByPlayer.isPlayerWhite(existsUser)), session);
|
||||
WebSocketUtils.sendPacket(roomByPlayer.getRoomInfo(users), session);
|
||||
}
|
||||
Session remove = sessions.remove(existsUser);
|
||||
log.info("session closed by another session");
|
||||
remove.close(new CloseReason(CloseReason.CloseCodes.NOT_CONSISTENT, "你的账号已在别处登录"));
|
||||
}
|
||||
for (String s : messageQueue) {
|
||||
this.onMessage(s, session);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@OnMessage
|
||||
public void onPong(PongMessage pongMessage, Session session) {
|
||||
ByteBuffer applicationData = pongMessage.getApplicationData();
|
||||
ByteBuf byteBuf = Unpooled.copiedBuffer(applicationData);
|
||||
long l = System.currentTimeMillis() - byteBuf.readLong();
|
||||
log.info("client sent pong response, latency is {}ms", l);
|
||||
pingPong.put(session, true);
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(String message, Session session) {
|
||||
if (!isLogin) {
|
||||
messageQueue.add(message);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JSONObject jsonObject = JSON.parseObject(message);
|
||||
String packetName = jsonObject.getString("name");
|
||||
if (packetName == null) {
|
||||
WebSocketUtils.sendPacket(new ErrorPacket("包内缺少name字段!"), session);
|
||||
}
|
||||
Object response = handleMessage(jsonObject, packetName, session);
|
||||
if (response != null) {
|
||||
WebSocketUtils.sendPacket(response, packetName, session);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
WebSocketUtils.sendPacket(new ErrorPacket("JSON格式错误"), session);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Object handleMessage(JSONObject object, String packetName, Session session) {
|
||||
if (packetName == null) return new ErrorPacket("错误的请求类型");
|
||||
try {
|
||||
Class<?> packetType = Class.forName("org.blue.club.entities.dto.chess.packet.request." + packetName + "Request");
|
||||
JSONObject payloadJson = object.getJSONObject("payload");
|
||||
if (payloadJson == null) {
|
||||
Field[] declaredFields = packetType.getDeclaredFields();
|
||||
if (declaredFields.length == 0) {
|
||||
payloadJson = new JSONObject();
|
||||
}
|
||||
}
|
||||
if (payloadJson == null) return new ErrorPacket("请求类型参数错误!");
|
||||
Object payload;
|
||||
try {
|
||||
payload = payloadJson.to(packetType);
|
||||
} catch (Exception e) {
|
||||
return new ErrorPacket("请求payload解析失败!");
|
||||
}
|
||||
if (payload == null) return null;
|
||||
return handlePacket(payload, session);
|
||||
} catch (ClassNotFoundException e) {
|
||||
return new ErrorPacket("错误的请求类型");
|
||||
}
|
||||
}
|
||||
|
||||
public Object handlePacket(Object payload, Session session) {
|
||||
String sessionId = session.getId();
|
||||
if (payload instanceof PlayerJoinRequest joinRequest) {
|
||||
Room roomByPlayer = getRoomByPlayer(sessionId);
|
||||
if (roomByPlayer != null) return new ErrorPacket("你已经加入过一个房间了");
|
||||
Room room = rooms.get(joinRequest.roomId());
|
||||
if (room == null) return new ErrorPacket("未知的房间");
|
||||
Optional<String> join = room.join(session, users.get(sessionId));
|
||||
if (join.isPresent()) return new ErrorPacket(join.get());
|
||||
room.broadcast(room.getRoomInfo(users));
|
||||
}
|
||||
if (payload instanceof RoomListRequest) {
|
||||
Collection<Room> values = rooms.values();
|
||||
return new RoomListPacket(values);
|
||||
}
|
||||
if (payload instanceof CreateRoomRequest) {
|
||||
Room room = new Room();
|
||||
UUID roomId = room.getId();
|
||||
rooms.put(roomId, room);
|
||||
return new RoomCreatedPacket(roomId);
|
||||
}
|
||||
if (payload instanceof PlaceChessPieceRequest placeChessPieceRequest) {
|
||||
int x = placeChessPieceRequest.x();
|
||||
int y = placeChessPieceRequest.y();
|
||||
Room roomByPlayer = getRoomByPlayer(sessionId);
|
||||
if (roomByPlayer == null) return new ErrorPacket("你还没加入房间呢");
|
||||
Optional<String> s = roomByPlayer.downPiece(x, y, sessionId);
|
||||
if (s.isPresent()) return new ErrorPacket(s.get());
|
||||
roomByPlayer.broadcast(roomByPlayer.getRoomInfo(users));
|
||||
Optional<Room.WinInfo> winInfo = roomByPlayer.isWin();
|
||||
winInfo.ifPresent(info -> {
|
||||
roomByPlayer.broadcast(new HasPlayerWinPacket(info));
|
||||
if (info.isWhite()) {
|
||||
WebSocketUtils.sendPacketIfPossible(new PlayerWinPacket(), roomByPlayer.getWhiteSession());
|
||||
WebSocketUtils.sendPacketIfPossible(new PlayerLosePacket(), roomByPlayer.getBlackSession());
|
||||
} else {
|
||||
WebSocketUtils.sendPacketIfPossible(new PlayerWinPacket(), roomByPlayer.getBlackSession());
|
||||
WebSocketUtils.sendPacketIfPossible(new PlayerLosePacket(), roomByPlayer.getWhiteSession());
|
||||
}
|
||||
roomByPlayer.setState(Room.RoomState.FINISHED);
|
||||
roomByPlayer.broadcast(roomByPlayer.getRoomInfo(users));
|
||||
});
|
||||
}
|
||||
if (payload instanceof ResetRoomRequest) {
|
||||
Room roomByPlayer = getRoomByPlayer(sessionId);
|
||||
if (roomByPlayer == null) return new ErrorPacket("你还没加入房间呢");
|
||||
roomByPlayer.requestRestart(session);
|
||||
roomByPlayer.broadcast(roomByPlayer.getRoomInfo(users));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Room getRoomByPlayer(String id) {
|
||||
for (Room value : rooms.values()) {
|
||||
if (value.isIn(id)) return value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void staticOnClose(Session session) {
|
||||
String sessionId = session.getId();
|
||||
Room roomByPlayer = getRoomByPlayer(sessionId);
|
||||
if (roomByPlayer != null) {
|
||||
roomByPlayer.leave(session);
|
||||
roomByPlayer.broadcast(roomByPlayer.getRoomInfo(users));
|
||||
}
|
||||
log.info("session closed {}", sessionId);
|
||||
sessions.remove(sessionId);
|
||||
users.remove(sessionId);
|
||||
pingPong.remove(session);
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(Session session) {
|
||||
staticOnClose(session);
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
@Scheduled(fixedDelay = 10000)
|
||||
public static void connectionManager() {
|
||||
for (Session value : sessions.values()) {
|
||||
if (!pingPong.getOrDefault(value, true)) {
|
||||
log.info("closed by connectionManager");
|
||||
if (value.isOpen()) {
|
||||
value.close(new CloseReason(CloseReason.CloseCodes.CLOSED_ABNORMALLY, "链接延迟过高"));
|
||||
continue;
|
||||
}
|
||||
staticOnClose(value);
|
||||
continue;
|
||||
}
|
||||
pingPong.put(value, false);
|
||||
log.info("send ping to session {}", value.getId());
|
||||
value.getAsyncRemote().sendPing(Unpooled.buffer().writeLong(System.currentTimeMillis()).nioBuffer());
|
||||
}
|
||||
Instant instant = new Date().toInstant();
|
||||
Instant before10Min = instant.plus(-10, ChronoUnit.MINUTES);
|
||||
rooms.entrySet().stream()
|
||||
.filter(e -> e.getValue().getState().equals(Room.RoomState.CREATED))
|
||||
.filter(e -> e.getValue().getLastStateChange().toInstant().isBefore(before10Min))
|
||||
.map(Map.Entry::getKey)
|
||||
.forEach(rooms::remove);
|
||||
rooms.values().forEach(Room::tryClean);
|
||||
}
|
||||
}
|
234
src/main/java/org/blue/club/entities/dto/chess/Room.java
Normal file
234
src/main/java/org/blue/club/entities/dto/chess/Room.java
Normal file
@ -0,0 +1,234 @@
|
||||
package org.blue.club.entities.dto.chess;
|
||||
|
||||
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import jakarta.websocket.Session;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Data;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import org.blue.club.entities.dto.chess.packet.PlayerJoinRoomPacket;
|
||||
import org.blue.club.entities.dto.chess.packet.PlayerLeavePacket;
|
||||
import org.blue.club.entities.dto.chess.packet.PlayerSideAllocationPacket;
|
||||
import org.blue.club.entities.dto.chess.packet.RoomInfoPacket;
|
||||
import org.blue.club.entities.dto.user.User;
|
||||
import org.blue.club.utils.WebSocketUtils;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@Data
|
||||
public class Room {
|
||||
private UUID id;
|
||||
private RoomState state;
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
private Session whiteSession;
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
private Session blackSession;
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
private byte[][] pieces;
|
||||
private boolean isWhiteAcceptRestart;
|
||||
private boolean isBlackAcceptRestart;
|
||||
private boolean canWhiteDown;
|
||||
@Setter(value = AccessLevel.PRIVATE)
|
||||
private Date lastStateChange;
|
||||
|
||||
public Room() {
|
||||
this.id = UUID.randomUUID();
|
||||
this.state = RoomState.CREATED;
|
||||
this.lastStateChange = new Date();
|
||||
resetPieces();
|
||||
}
|
||||
|
||||
public void setState(RoomState state) {
|
||||
if (state == this.state) return;
|
||||
this.state = state;
|
||||
this.lastStateChange = new Date();
|
||||
}
|
||||
|
||||
public void resetPieces() {
|
||||
this.canWhiteDown = false;
|
||||
this.pieces = new byte[16][16];
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int j = 0; j < 16; j++) {
|
||||
this.pieces[i][j] = -1;
|
||||
}
|
||||
}
|
||||
isWhiteAcceptRestart = false;
|
||||
isBlackAcceptRestart = false;
|
||||
}
|
||||
|
||||
public boolean isFull() {
|
||||
return Objects.nonNull(this.whiteSession) && Objects.nonNull(this.blackSession);
|
||||
}
|
||||
|
||||
public Optional<String> join(Session session, User user) {
|
||||
if (this.getState() == RoomState.GAMING) {
|
||||
return Optional.of("你所加入的房间正在游戏!");
|
||||
}
|
||||
if (this.isFull()) {
|
||||
return Optional.of("所加入的房间已满");
|
||||
}
|
||||
if (Objects.nonNull(this.whiteSession)) {
|
||||
WebSocketUtils.sendPacket(new PlayerSideAllocationPacket(false), session);
|
||||
WebSocketUtils.sendPacketIfPossible(new PlayerJoinRoomPacket(user, this), whiteSession);
|
||||
this.blackSession = session;
|
||||
} else {
|
||||
WebSocketUtils.sendPacket(new PlayerSideAllocationPacket(true), session);
|
||||
WebSocketUtils.sendPacketIfPossible(new PlayerJoinRoomPacket(user, this), blackSession);
|
||||
this.whiteSession = session;
|
||||
}
|
||||
if (this.isFull()) {
|
||||
this.setState(RoomState.GAMING);
|
||||
} else {
|
||||
this.setState(RoomState.WAITING);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void leave(Session session) {
|
||||
String sessionId = session.getId();
|
||||
if (Objects.nonNull(this.blackSession) && this.blackSession.getId().equals(sessionId)) {
|
||||
WebSocketUtils.sendPacketIfPossible(new PlayerLeavePacket(sessionId), whiteSession);
|
||||
this.blackSession = null;
|
||||
this.setState(RoomState.WAITING);
|
||||
}
|
||||
if (Objects.nonNull(this.whiteSession) && this.whiteSession.getId().equals(sessionId)) {
|
||||
WebSocketUtils.sendPacketIfPossible(new PlayerLeavePacket(sessionId), blackSession);
|
||||
this.whiteSession = null;
|
||||
this.setState(RoomState.WAITING);
|
||||
}
|
||||
if (Objects.isNull(this.blackSession) && Objects.isNull(this.whiteSession)) {
|
||||
this.setState(RoomState.CREATED);
|
||||
}
|
||||
}
|
||||
|
||||
public RoomInfoPacket getRoomInfo(Map<String, User> users) {
|
||||
Session whiteSession = this.getWhiteSession();
|
||||
Session blackSession = this.getBlackSession();
|
||||
User whiteUser = whiteSession != null ? users.get(whiteSession.getId()) : null;
|
||||
User blackUser = blackSession != null ? users.get(blackSession.getId()) : null;
|
||||
return new RoomInfoPacket(this.id, whiteUser, blackUser, this.state, pieces, this.isWhiteAcceptRestart, this.isBlackAcceptRestart, this.canWhiteDown);
|
||||
}
|
||||
|
||||
public void broadcast(Object packet) {
|
||||
if (packet == null) return;
|
||||
WebSocketUtils.sendPacketIfPossible(packet, whiteSession);
|
||||
WebSocketUtils.sendPacketIfPossible(packet, blackSession);
|
||||
}
|
||||
|
||||
public boolean isIn(String sessionId) {
|
||||
return (Objects.nonNull(whiteSession) && whiteSession.getId().equals(sessionId)) || (Objects.nonNull(blackSession) && blackSession.getId().equals(sessionId));
|
||||
}
|
||||
|
||||
public Optional<String> downPiece(int x, int y, String sessionId) {
|
||||
if (!this.getState().equals(RoomState.GAMING)) return Optional.of("游戏暂未开始!");
|
||||
byte originalValue = this.pieces[y][x];
|
||||
if (originalValue != -1) return Optional.of("此位置已落子!");
|
||||
if (whiteSession.getId().equals(sessionId)) {
|
||||
if (!canWhiteDown) return Optional.of("请等待对手落子");
|
||||
canWhiteDown = false;
|
||||
this.pieces[y][x] = 1;
|
||||
} else {
|
||||
if (canWhiteDown) return Optional.of("请等待对手落子");
|
||||
canWhiteDown = true;
|
||||
this.pieces[y][x] = 0;
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public Optional<WinInfo> isWin() {
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
byte startPointType = this.pieces[y][x];
|
||||
if (startPointType == -1) continue;
|
||||
for (Faces value : Faces.values()) {
|
||||
boolean facePossible = true;
|
||||
for (int i = 1; i < 5; i++) {
|
||||
int totalXDelta = value.xDelta * i;
|
||||
int totalYDelta = value.yDelta * i;
|
||||
int fullyX = x + totalXDelta;
|
||||
int fullyY = y + totalYDelta;
|
||||
if (fullyX < 0 || fullyX > 15 || fullyY < 0 || fullyY > 15) {
|
||||
facePossible = false;
|
||||
break;
|
||||
}
|
||||
if (this.pieces[fullyY][fullyX] != startPointType) {
|
||||
facePossible = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!facePossible) continue;
|
||||
return Optional.of(new WinInfo(value, x, y, startPointType == 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public void requestRestart(Session session) {
|
||||
String sessionId = session.getId();
|
||||
if (whiteSession == null || sessionId.equals(whiteSession.getId())) {
|
||||
isWhiteAcceptRestart = true;
|
||||
}
|
||||
if (blackSession == null || sessionId.equals(blackSession.getId())) {
|
||||
isBlackAcceptRestart = true;
|
||||
}
|
||||
if (isBlackAcceptRestart && isWhiteAcceptRestart) {
|
||||
this.resetPieces();
|
||||
if (whiteSession == null || blackSession == null) {
|
||||
this.setState(RoomState.WAITING);
|
||||
return;
|
||||
}
|
||||
this.setState(RoomState.GAMING);
|
||||
}
|
||||
}
|
||||
|
||||
public void replace(String existsUser, Session session) {
|
||||
if (Objects.nonNull(this.whiteSession) && whiteSession.getId().equals(existsUser)) {
|
||||
whiteSession = session;
|
||||
}
|
||||
if (Objects.nonNull(this.blackSession) && blackSession.getId().equals(existsUser)) {
|
||||
blackSession = session;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPlayerWhite(String sessionId) {
|
||||
return sessionId.equals(whiteSession.getId());
|
||||
}
|
||||
|
||||
public void tryClean() {
|
||||
if (whiteSession != null) {
|
||||
if (!whiteSession.isOpen()) {
|
||||
this.leave(whiteSession);
|
||||
}
|
||||
}
|
||||
if (blackSession != null) {
|
||||
if (!blackSession.isOpen()) {
|
||||
this.leave(blackSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum RoomState {
|
||||
CREATED,
|
||||
WAITING,
|
||||
GAMING,
|
||||
FINISHED
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public enum Faces {
|
||||
UP(0, -1),
|
||||
UP_RIGHT(1, -1),
|
||||
RIGHT(1, 0),
|
||||
DOWN_RIGHT(1, 1),
|
||||
DOWN(0, 1),
|
||||
DOWN_LEFT(-1, 1),
|
||||
LEFT(-1, 0),
|
||||
UP_LEFT(-1, -1);
|
||||
public final int xDelta, yDelta;
|
||||
}
|
||||
|
||||
public record WinInfo(Faces face, int originalX, int originalY, boolean isWhite) {
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
import jakarta.annotation.Nullable;
|
||||
import lombok.Data;
|
||||
import lombok.NonNull;
|
||||
|
||||
@Data
|
||||
public class BaseWebSocketPacket {
|
||||
private String name;
|
||||
private Object payload;
|
||||
@Nullable
|
||||
private String originalPacketName;
|
||||
|
||||
public BaseWebSocketPacket(Object payload) {
|
||||
Class<?> aClass = payload.getClass();
|
||||
this.name = aClass.getSimpleName().replace("Packet", "");
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
public BaseWebSocketPacket(Object payload, @NonNull String originalPacketName) {
|
||||
this(payload);
|
||||
this.originalPacketName = originalPacketName;
|
||||
}
|
||||
|
||||
public static BaseWebSocketPacket of(Object payload) {
|
||||
return new BaseWebSocketPacket(payload);
|
||||
}
|
||||
|
||||
public static BaseWebSocketPacket of(Object packet, @NonNull String originalPacketName) {
|
||||
return new BaseWebSocketPacket(packet, originalPacketName);
|
||||
}
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
public record ErrorPacket(String reason) {
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
import org.blue.club.entities.dto.chess.Room;
|
||||
|
||||
public record HasPlayerWinPacket(Room.WinInfo winInfo) {
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
import org.blue.club.entities.dto.chess.Room;
|
||||
import org.blue.club.entities.dto.user.User;
|
||||
|
||||
public record PlayerJoinRoomPacket(User user, Room room) {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
public record PlayerLeavePacket(String player) {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
public record PlayerLosePacket() {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
public record PlayerSideAllocationPacket(boolean isWhite) {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
public record PlayerWinPacket() {
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record RoomCreatedPacket(UUID roomId) {
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
import org.blue.club.entities.dto.chess.Room;
|
||||
import org.blue.club.entities.dto.user.User;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record RoomInfoPacket(UUID roomId, User whiteUser, User blackUser, Room.RoomState state, byte[][] pieces,
|
||||
boolean whiteRequestRestart, boolean blackRequestRestart, boolean canWhiteDown) {
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
import org.blue.club.entities.dto.chess.Room;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public record RoomListPacket(Collection<Room> rooms) {
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.blue.club.entities.dto.chess.packet;
|
||||
|
||||
import org.blue.club.entities.dto.user.User;
|
||||
|
||||
public record UserInfoPacket(User user) {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet.request;
|
||||
|
||||
public record CreateRoomRequest() {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet.request;
|
||||
|
||||
public record PlaceChessPieceRequest(int x, int y) {
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
package org.blue.club.entities.dto.chess.packet.request;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record PlayerJoinRequest(UUID roomId) {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet.request;
|
||||
|
||||
public record ResetRoomRequest() {
|
||||
}
|
@ -0,0 +1,4 @@
|
||||
package org.blue.club.entities.dto.chess.packet.request;
|
||||
|
||||
public record RoomListRequest() {
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
package org.blue.club.schedule;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.blue.club.dao.redis.AvatarOperationDao;
|
||||
import org.blue.club.dao.redis.VerifyDao;
|
||||
import org.blue.club.entities.vo.VerifyVo;
|
||||
import org.blue.club.entities.vo.data.AvatarTmpVo;
|
||||
import org.blue.club.utils.iop.FileUtils;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.File;
|
||||
import java.time.Instant;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Date;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class RemoveExpireDataSchedule {
|
||||
private final AvatarOperationDao avatarDao;
|
||||
private final File tmpFolder;
|
||||
private final VerifyDao verifyDao;
|
||||
private final FileUtils fileUtils;
|
||||
|
||||
@Scheduled(fixedDelay = 1000)
|
||||
public void removeTempAvatar() {
|
||||
Instant now = Instant.now();
|
||||
for (AvatarTmpVo avatarTmpVo : avatarDao.findAll()) {
|
||||
Date time = avatarTmpVo.createTime();
|
||||
Instant instant = time.toInstant();
|
||||
Instant expireTime = instant.plus(15, ChronoUnit.MINUTES);
|
||||
if (expireTime.isAfter(now)) {
|
||||
String s = avatarTmpVo.operationCode();
|
||||
File deleteFile = new File(tmpFolder, s);
|
||||
if (deleteFile.exists()) {
|
||||
fileUtils.tryDeleteOrDeleteOnExit(deleteFile);
|
||||
}
|
||||
avatarDao.delete(avatarTmpVo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Scheduled(fixedDelay = 1000)
|
||||
public void removeExpiredVerify() {
|
||||
Instant now = Instant.now();
|
||||
for (VerifyVo verifyVo : verifyDao.findAll()) {
|
||||
Instant instant = verifyVo.createTime().toInstant();
|
||||
Instant expireTime = instant.plus(15, ChronoUnit.MINUTES);
|
||||
if (expireTime.isAfter(now)) {
|
||||
verifyDao.delete(verifyVo);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
34
src/main/java/org/blue/club/utils/WebSocketUtils.java
Normal file
34
src/main/java/org/blue/club/utils/WebSocketUtils.java
Normal file
@ -0,0 +1,34 @@
|
||||
package org.blue.club.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import jakarta.annotation.Nullable;
|
||||
import jakarta.websocket.Session;
|
||||
import lombok.NonNull;
|
||||
import lombok.SneakyThrows;
|
||||
import org.blue.club.entities.dto.chess.packet.BaseWebSocketPacket;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class WebSocketUtils {
|
||||
@SneakyThrows
|
||||
public static void sendJsonMessage(@NonNull JSONObject message, @NonNull Session session) {
|
||||
session.getBasicRemote().sendText(message.toJSONString());
|
||||
}
|
||||
|
||||
public static void sendMessage(@NonNull Object object, @NonNull Session session) {
|
||||
sendJsonMessage(JSONObject.from(object), session);
|
||||
}
|
||||
|
||||
public static void sendPacket(@NonNull Object packet, @NonNull Session session) {
|
||||
sendMessage(BaseWebSocketPacket.of(packet), session);
|
||||
}
|
||||
|
||||
public static void sendPacket(@NonNull Object packet, String originalPacketName, @NonNull Session session) {
|
||||
sendMessage(BaseWebSocketPacket.of(packet, originalPacketName), session);
|
||||
}
|
||||
|
||||
public static void sendPacketIfPossible(@NonNull Object packet, @Nullable Session session) {
|
||||
if (Objects.isNull(session)) return;
|
||||
sendPacket(packet, session);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user