package com.zhaidaosi.game.jgframework.session; import com.zhaidaosi.game.jgframework.Boot; import com.zhaidaosi.game.jgframework.Router; import com.zhaidaosi.game.jgframework.common.queue.BaseQueue; import com.zhaidaosi.game.jgframework.common.queue.BaseQueueElement; import com.zhaidaosi.game.jgframework.connector.IBaseConnector; import com.zhaidaosi.game.jgframework.message.IBaseMessage; import com.zhaidaosi.game.jgframework.message.InMessage; import com.zhaidaosi.game.jgframework.message.OutMessage; import com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter; import io.netty.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.List; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; public class SessionManager { public final static String SECRET = "secret"; public final static int ADD_SESSION_SUCC = 1; public final static int ADD_SESSION_ERROR = -1; public final static int ADD_SESSION_WAIT = 0; private static final Logger log = LoggerFactory.getLogger(SessionManager.class); private static IBaseSecretFactory secretFactory = new BaseSecretFactory(); private static ConcurrentMap<Integer, Channel> userIdChannels = new ConcurrentHashMap<>(); private static ConcurrentMap<Integer, BaseQueueElement<Channel>> waitUserIdChannels = new ConcurrentHashMap<>(); private static BaseQueue<Channel> waitQueue = new BaseQueue<>(); private static Timer timer; private static int maxUser = 0; public static int checkSession(InMessage msg, Channel ch) { IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); if (player == null) { return ADD_SESSION_ERROR; } if (player.getId() <= 0) { Object secret = msg.getMember(SECRET); if (secret == null || secret.equals("")) { return ADD_SESSION_ERROR; } try { int userId = checkSecret((String) secret); if (userId == 0) { return ADD_SESSION_ERROR; } player.setId(userId); return SessionManager.addSession(player, ch); } catch (Exception e) { return ADD_SESSION_ERROR; } } if (maxUser > 0 && player.isInQueue()) { return ADD_SESSION_WAIT; } return ADD_SESSION_SUCC; } /** * 加入session * @param player * @param ch * @return */ private static int addSession(IBaseCharacter player, Channel ch) { int userId; if (player == null || (userId = player.getId()) <= 0) { return ADD_SESSION_ERROR; } Channel _ch = userIdChannels.get(userId); BaseQueueElement<Channel> queueElement = null; if (_ch == null && maxUser > 0) { queueElement = waitUserIdChannels.get(userId); if (queueElement != null) { _ch = queueElement.getValue(); } } boolean same = _ch != null && _ch.hashCode() == ch.hashCode(); if (_ch != null && !same) { IBaseCharacter _player = _ch.attr(IBaseConnector.PLAYER).get(); if (_player != null) { _player.setId(0); // 保持排队名次 if (queueElement != null) { player.setIsInQueue(true); queueElement.setValue(ch); } } _ch.close(); } if (maxUser > 0) { if (queueElement != null) { return ADD_SESSION_WAIT; } else if (userIdChannels.size() >= maxUser) { player.setIsInQueue(true); BaseQueueElement<Channel> element = waitQueue.put(ch); if (_ch == null || !same) { waitUserIdChannels.put(userId, element); } return ADD_SESSION_WAIT; } } if (_ch == null || !same) { userIdChannels.put(userId, ch); } player.loginHook(); return ADD_SESSION_SUCC; } public static void removeSession(Channel ch) { IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); if (player != null) { int userId = player.getId(); if (maxUser > 0 && player.isInQueue()) { if (userId > 0) { BaseQueueElement<Channel> queueElement = waitUserIdChannels.get(userId); waitUserIdChannels.remove(userId); waitQueue.remove(queueElement); } } else { if (userId > 0) { userIdChannels.remove(userId); } player.logoutHook(); } } } public static List<IBaseCharacter> getOnlineUser() { List<IBaseCharacter> onlineUser = new ArrayList<IBaseCharacter>(); for (Channel ch : userIdChannels.values()) { IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); if (player != null && player.getId() > 0) { onlineUser.add(player); } } return onlineUser; } public static IBaseCharacter getPlayerByUserId(Integer uid) { Channel ch = userIdChannels.get(uid); IBaseCharacter player = ch == null ? null : ch.attr(IBaseConnector.PLAYER).get(); return (player != null && player.getId() > 0) ? player : null; } public static boolean isAuthHandler(InMessage msg) { return msg.getH().startsWith(Boot.getAuthHandler()); } public static String getServerIp(int userId) { int AuthCount = Boot.getServiceCount(); int index = userId % AuthCount; return Boot.getServiceIps().get(index); } public static String createSecret(int userId) throws Exception { return secretFactory.createSecret(userId); } private static int checkSecret(String secret) throws Exception { return secretFactory.checkSecret(secret); } public static void init() { if (maxUser > 0) { initTimer(); } } public static void destroy() { userIdChannels.clear(); if (timer != null) { timer.cancel(); timer = null; } if (maxUser > 0) { waitUserIdChannels.clear(); waitQueue.clear(); } } public static long getWaitCount() { return waitQueue.size(); } public static int getUserCount() { return userIdChannels.size(); } public static ConcurrentMap<Integer, Channel> getChannels() { return userIdChannels; } public static void setSercretFactory(IBaseSecretFactory secretFactory) { SessionManager.secretFactory = secretFactory; } public static void setMaxUser(int max) { if (max > 0) { maxUser = max; } } private static void initTimer() { if (timer == null) { timer = new Timer("QueueTimerTask"); timer.schedule(new QueueTimerTask(), 10000, 10000); } } public static IBaseMessage getWaitMessage(IBaseCharacter player) { long index = 0; if (player != null && player.isInQueue()) { BaseQueueElement<Channel> queueElement = waitUserIdChannels.get(player.getId()); index = waitQueue.findIndex(queueElement); } return OutMessage.showSucc(index, Router.WAIT_HANDLERNAME); } private static class QueueTimerTask extends TimerTask { @Override public void run() { try { while (userIdChannels.size() < maxUser && waitQueue.size() > 0) { BaseQueueElement<Channel> element = waitQueue.take(); if (element == null) { continue; } Channel ch = element.getValue(); if (ch == null) { continue; } IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); if (player == null) { continue; } int userId = player.getId(); if (userId <= 0) { continue; } waitUserIdChannels.remove(userId); player.setIsInQueue(false); userIdChannels.put(userId, ch); ch.writeAndFlush(getWaitMessage(player)); } BaseQueueElement<Channel> start = waitQueue.getStart(); while (start != null) { Channel ch = start.getValue(); IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get(); ch.writeAndFlush(getWaitMessage(player)); start = start.getNext(); } } catch (Exception e) { log.error(e.getMessage(), e); } } } }