feat: 在 Redis 锁定服务器 ID
This commit is contained in:
@@ -13,6 +13,7 @@ import cn.hamster3.mc.plugin.ball.common.event.server.ServerOfflineEvent;
|
||||
import cn.hamster3.mc.plugin.ball.common.listener.BallCommonListener;
|
||||
import cn.hamster3.mc.plugin.ball.common.listener.BallDebugListener;
|
||||
import cn.hamster3.mc.plugin.ball.common.listener.BallRedisListener;
|
||||
import cn.hamster3.mc.plugin.ball.common.thread.LockUpdateThread;
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.config.ConfigSection;
|
||||
import cn.hamster3.mc.plugin.core.common.data.DisplayMessage;
|
||||
@@ -29,6 +30,8 @@ import javax.sql.DataSource;
|
||||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ScheduledFuture;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
@Getter
|
||||
@@ -66,8 +69,8 @@ public abstract class BallAPI {
|
||||
|
||||
@NotNull
|
||||
private final Jedis redisSub;
|
||||
@NotNull
|
||||
private final Jedis redisPub;
|
||||
@Nullable
|
||||
private ScheduledFuture<?> lockUpdater;
|
||||
|
||||
public BallAPI(@NotNull ConfigSection config, BallServerType type) {
|
||||
ConfigSection serverInfoConfig = config.getSection("server-info");
|
||||
@@ -89,7 +92,6 @@ public abstract class BallAPI {
|
||||
allServerInfo = new ConcurrentHashMap<>();
|
||||
allPlayerInfo = new ConcurrentHashMap<>();
|
||||
redisSub = CoreAPI.getInstance().getJedisPool().getResource();
|
||||
redisPub = CoreAPI.getInstance().getJedisPool().getResource();
|
||||
getLogger().info("频道前缀: " + ballConfig.getChannelPrefix());
|
||||
getLogger().info("启用子服更新玩家状态: " + ballConfig.isGameServerUpdatePlayerInfo());
|
||||
if (ballConfig.isGameServerUpdatePlayerInfo()) {
|
||||
@@ -102,6 +104,29 @@ public abstract class BallAPI {
|
||||
}
|
||||
|
||||
protected void enable() throws SQLException, InterruptedException {
|
||||
try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) {
|
||||
String key = "HamsterBall:ServerInfo:" + localServerInfo.getId();
|
||||
if (jedis.exists(key)) {
|
||||
throw new IllegalStateException("已经有一个服务器占用了该 ID");
|
||||
}
|
||||
jedis.hset(key, "id", localServerInfo.getId());
|
||||
jedis.hset(key, "name", localServerInfo.getName());
|
||||
jedis.hset(key, "type", localServerInfo.getType().name());
|
||||
jedis.hset(key, "host", localServerInfo.getHost());
|
||||
jedis.hset(key, "port", String.valueOf(localServerInfo.getPort()));
|
||||
jedis.expire(key, 180);
|
||||
lockUpdater = CoreAPI.getInstance().getScheduledService().scheduleAtFixedRate(LockUpdateThread.INSTANCE, 1, 1, TimeUnit.MINUTES);
|
||||
for (String serverInfoKey : jedis.keys("HamsterBall:ServerInfo:*")) {
|
||||
BallServerInfo info = new BallServerInfo(
|
||||
jedis.hget(serverInfoKey, "id"),
|
||||
jedis.hget(serverInfoKey, "name"),
|
||||
BallServerType.valueOf(jedis.hget(serverInfoKey, "type")),
|
||||
jedis.hget(serverInfoKey, "host"),
|
||||
Integer.parseInt(jedis.hget(serverInfoKey, "port"))
|
||||
);
|
||||
allServerInfo.put(info.getId(), info);
|
||||
}
|
||||
}
|
||||
try (Connection connection = getDatasource().getConnection()) {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS `hamster_ball_player_info`(" +
|
||||
@@ -111,44 +136,11 @@ public abstract class BallAPI {
|
||||
"`proxy_server` VARCHAR(32) NOT NULL," +
|
||||
"`online` BOOLEAN NOT NULL" +
|
||||
") CHARSET utf8mb4;");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS `hamster_ball_server_info`(" +
|
||||
"`id` VARCHAR(32) PRIMARY KEY NOT NULL," +
|
||||
"`name` VARCHAR(32) NOT NULL," +
|
||||
"`type` VARCHAR(16) NOT NULL," +
|
||||
"`host` VARCHAR(32) NOT NULL," +
|
||||
"`port` INT NOT NULL" +
|
||||
") CHARSET utf8mb4;");
|
||||
statement.execute("CREATE TABLE IF NOT EXISTS `hamster_ball_cached_message`(" +
|
||||
"`uuid` CHAR(36) NOT NULL," +
|
||||
"`message` TEXT NOT NULL" +
|
||||
") CHARSET utf8mb4;");
|
||||
}
|
||||
try (PreparedStatement statement = connection.prepareStatement(
|
||||
"REPLACE INTO `hamster_ball_server_info` VALUES(?, ?, ?, ?, ?);"
|
||||
)) {
|
||||
statement.setString(1, localServerInfo.getId());
|
||||
statement.setString(2, localServerInfo.getName());
|
||||
statement.setString(3, localServerInfo.getType().name());
|
||||
statement.setString(4, localServerInfo.getHost());
|
||||
statement.setInt(5, localServerInfo.getPort());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
try (PreparedStatement statement = connection.prepareStatement(
|
||||
"SELECT * FROM `hamster_ball_server_info`;"
|
||||
)) {
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
while (set.next()) {
|
||||
String serverID = set.getString("id");
|
||||
allServerInfo.put(serverID, new BallServerInfo(
|
||||
serverID,
|
||||
set.getString("name"),
|
||||
BallServerType.valueOf(set.getString("type")),
|
||||
set.getString("host"),
|
||||
set.getInt("port")
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (getBallConfig().isGameServerUpdatePlayerInfo()) {
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
try (ResultSet set = statement.executeQuery(String.format(
|
||||
@@ -193,14 +185,15 @@ public abstract class BallAPI {
|
||||
sendBallMessage(BallAPI.BALL_CHANNEL, new BallMessage(
|
||||
BallActions.ServerOffline.name(), new ServerOfflineEvent(getLocalServerInfo())
|
||||
), false, true);
|
||||
|
||||
try (Connection connection = getDatasource().getConnection()) {
|
||||
try (PreparedStatement statement = connection.prepareStatement(
|
||||
"DELETE FROM `hamster_ball_server_info` WHERE `id`=?;"
|
||||
)) {
|
||||
statement.setString(1, getLocalServerId());
|
||||
statement.executeUpdate();
|
||||
if (lockUpdater != null) {
|
||||
lockUpdater.cancel(true);
|
||||
lockUpdater = null;
|
||||
try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) {
|
||||
String key = "HamsterBall:ServerInfo:" + localServerInfo.getId();
|
||||
jedis.del(key);
|
||||
}
|
||||
}
|
||||
try (Connection connection = getDatasource().getConnection()) {
|
||||
try (PreparedStatement statement = connection.prepareStatement(
|
||||
"UPDATE `hamster_ball_player_info` SET `online`=false WHERE `game_server`=? OR `proxy_server`=?"
|
||||
)) {
|
||||
@@ -210,7 +203,6 @@ public abstract class BallAPI {
|
||||
}
|
||||
}
|
||||
redisSub.close();
|
||||
redisPub.close();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -493,12 +485,17 @@ public abstract class BallAPI {
|
||||
channel = ballConfig.getChannelPrefix() + channel;
|
||||
}
|
||||
if (block) {
|
||||
redisPub.publish(channel, CoreAPI.getInstance().getGson().toJson(message));
|
||||
try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) {
|
||||
jedis.publish(channel, CoreAPI.getInstance().getGson().toJson(message));
|
||||
}
|
||||
eventBus.post(new MessageSentEvent(channel, message));
|
||||
} else {
|
||||
@NotNull String finalChannel = channel;
|
||||
CoreAPI.getInstance().getExecutorService().submit(() -> {
|
||||
redisPub.publish(finalChannel, CoreAPI.getInstance().getGson().toJson(message));
|
||||
try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) {
|
||||
jedis.publish(finalChannel, CoreAPI.getInstance().getGson().toJson(message));
|
||||
}
|
||||
eventBus.post(new MessageSentEvent(finalChannel, message));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@@ -45,13 +45,11 @@ public class BallServerInfo {
|
||||
|
||||
public BallServerInfo(@NotNull ConfigSection config, BallServerType type) {
|
||||
Map<String, String> env = System.getenv();
|
||||
id = env.getOrDefault("BALL_LOCAL_SERVER_INFO_ID", config.getString("id"));
|
||||
name = env.getOrDefault("BALL_LOCAL_SERVER_INFO_NAME", config.getString("name"));
|
||||
id = env.getOrDefault("BALL_SERVER_ID", config.getString("id"));
|
||||
name = env.getOrDefault("BALL_SERVER_NAME", config.getString("name"));
|
||||
this.type = type;
|
||||
host = env.getOrDefault("BALL_LOCAL_SERVER_IP", config.getString("host"));
|
||||
port = Integer.parseInt(
|
||||
env.getOrDefault("BALL_LOCAL_SERVER_PORT", String.valueOf(config.getInt("port")))
|
||||
);
|
||||
host = "0.0.0.0";
|
||||
port = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@@ -0,0 +1,20 @@
|
||||
package cn.hamster3.mc.plugin.ball.common.thread;
|
||||
|
||||
import cn.hamster3.mc.plugin.ball.common.api.BallAPI;
|
||||
import cn.hamster3.mc.plugin.core.common.api.CoreAPI;
|
||||
import cn.hamster3.mc.plugin.core.lib.redis.clients.jedis.Jedis;
|
||||
|
||||
public class LockUpdateThread implements Runnable {
|
||||
public static final LockUpdateThread INSTANCE = new LockUpdateThread();
|
||||
|
||||
private LockUpdateThread() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
String key = "HamsterBall:ServerInfo:" + BallAPI.getInstance().getLocalServerInfo().getId();
|
||||
try (Jedis jedis = CoreAPI.getInstance().getJedisPool().getResource()) {
|
||||
jedis.expire(key, 180);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user