package com.jmfy.controller; import com.jmfy.dao.ServerInfoDao; import com.jmfy.handler.GMHandler; import com.jmfy.model.AutoServerSetting; import com.jmfy.model.CServerOpenTime; import com.jmfy.model.ServerInfo; import com.jmfy.model.vo.PowersEnum; import com.jmfy.model.vo.ServerInfoVo; import com.jmfy.model.vo.ServerStatusEnum; import com.jmfy.redisProperties.RedisUserKey; import com.jmfy.utils.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import java.util.*; import java.util.concurrent.TimeUnit; /** * @author hj */ @Controller public class ServerInfoController { private static final Logger LOGGER = LoggerFactory.getLogger(ServerInfoController.class); @Resource private ServerInfoDao serverInfoDao; @Resource private CommonManager commonManager; @Resource private AutoServerManager autoServerManager; private static int state = 0; /** * 各服参数 */ private static ExpiryMap serverStatus = new ExpiryMap<>(); /** * 游戏服端口状态 * key: 服务器id * value : [0]:游戏服端口状态, [1]:支付端口状态 */ private static ExpiryMap portStatusMap = new ExpiryMap<>(); /** * 服务器信息界面 * @param map * @return * @throws Exception */ @RequestMapping(value = "/findServerInfo", method = {RequestMethod.POST, RequestMethod.GET}) public String findServerInfo(ModelMap map, int quick) throws Exception { List serverInfoVos = new ArrayList<>(); List serverInfos = serverInfoDao.getAllServerInfo(); for (ServerInfo serverInfo : serverInfos) { if (null == serverInfo.getServer_id()) { continue; } ServerInfoVo serverInfoVo = createServerVo(serverInfo,quick); serverInfoVos.add(serverInfoVo); } map.addAttribute("serverInfos", serverInfoVos); map.addAttribute("state", state); return "findServerInfo"; } /** * 服务器信息界面 * @return */ @RequestMapping(value = "/findServerInfoNotCache", method = {RequestMethod.POST, RequestMethod.GET}) public String findServerInfoNotCache(ModelMap map) throws Exception { return findServerInfo(map,1); } /** * 刷新缓存 */ private void refreshCache(){ state = 1; try { // 更新全部服务器得信息 List allServerInfo = serverInfoDao.getAllServerInfo(); for (ServerInfo info : allServerInfo) { getServerOpenTime(info.getServer_id(),1); } // 更新端口信息 // portListenHandler(); } catch (Exception e) { e.printStackTrace(); } LoginController.addQueue("服务器缓存刷新完成!"); state = 0; } @PostConstruct public void onstart(){ // 定时任务延迟1分钟执行,每隔俩小时执行一次 TaskKit.scheduleAtFixedRate(this::refreshCache,10,7200,TimeUnit.SECONDS); } /** * 获取服务器开启状态 * @param serverId * @param quick 0:走缓存, 1:不走缓存 * @return * @throws Exception */ public CServerOpenTime getServerOpenTime(String serverId,int quick) throws Exception { CServerOpenTime openTime = serverStatus.get(serverId); if (openTime != null && quick == 0){ return openTime; } CServerOpenTime cServerOpenTime = serverInfoDao.getOpenServerTime(serverId); if (cServerOpenTime == null){ return null; } serverStatus.put(serverId,cServerOpenTime,DateUtil.ONE_HOUR); return cServerOpenTime; } /** * 创建服务器包装类 * @param serverInfo * @param quick * @return * @throws Exception */ private ServerInfoVo createServerVo(ServerInfo serverInfo,int quick) throws Exception { ServerInfoVo vo = new ServerInfoVo(serverInfo); // ip+端口 vo.setIpAndPort(serverInfo.getIp()+":"+serverInfo.getPort()); // 服务器配置,开服时间,重启时间,版本号 CServerOpenTime openTime = getServerOpenTime(serverInfo.getServer_id(), quick); if (openTime != null){ vo.setOpenTime(openTime.getOpenTime()); vo.setRestartTime(openTime.getRestartTime()); vo.setVersion(openTime.getVersion()); } // 开服方法 String openType = "手动开服"; AutoServerSetting setting = RedisUtil.getInstence().getMapValue(RedisUserKey.AUTO_START_SERVER_SETTING, "1", "1", AutoServerSetting.class, -1); if (setting != null && "1".equals(setting.getState())){ openType = "1".equals(setting.getChoose())?"按量开服":"自动开服"; } vo.setOpenType(openType); // gm跨服分组 vo.setCrossGroupId(getServerGroupId(serverInfo.getServer_id())); // 游戏服务器跨服分组 vo.setOldGroupId(getGameServerGroupId(serverInfo.getServer_id())); return vo; } /** * 编辑服务器 * @param map * @param id * @return * @throws Exception */ @RequestMapping(value = "/toServerInfoEdit", method = {RequestMethod.POST, RequestMethod.GET}) public String toServerInfoEdit(ModelMap map, int id) throws Exception { ServerInfo serverInfo = serverInfoDao.getServerInfo(String.valueOf(id)); ServerInfoVo vo = createServerVo(serverInfo, 0); map.addAttribute("serverInfo", vo); return "serverInfoEdit"; } /** * 删除服务器 * @param request * @return * @throws Exception */ @RequestMapping(value = "/deleteServer", method = {RequestMethod.POST, RequestMethod.GET}) public @ResponseBody int deleteServer(HttpServletRequest request) throws Exception { boolean power = commonManager.verifyPower(request, PowersEnum.DELETE_SERVER_PERMISSIONS); if (!power){ return 2; } String serverId = request.getParameter("serverId"); if (serverId == null){ return 0; } serverInfoDao.deleteServer(serverId); return 1; } /** * 迁移服务器 * @param request * @return * @throws Exception */ @RequestMapping(value = "/transferServer", method = {RequestMethod.POST, RequestMethod.GET}) public @ResponseBody int transferServer(HttpServletRequest request) throws Exception { boolean power = commonManager.verifyPower(request, PowersEnum.TRANSFER_SERVER_PERMISSIONS); if (!power){ return 0; } int serverId = Integer.parseInt(request.getParameter("serverId")); String ip = request.getParameter("ip"); int port = Integer.parseInt(request.getParameter("port")); int coreNum = Integer.parseInt(request.getParameter("coreName")); int count = Integer.parseInt(request.getParameter("count")); Map serverMap = serverInfoDao.getAllServerMap(); for (int i = 0; i < count; i++) { ServerInfo info = serverMap.get(String.valueOf(serverId+i)); if (info == null){ LOGGER.error("服务器不存在:{}",serverId+i); continue; } info.setIp(ip); info.setPort(String.valueOf(port+i)); info.setCoreName("core"+(coreNum+i)); serverInfoDao.updateServerInfo(info); } return 1; } /** * 修改服务器信息 * @param vo * @return * @throws Exception */ @RequestMapping(value = "/serverEdit", method = {RequestMethod.POST, RequestMethod.GET}) public @ResponseBody int serverEdit(@RequestBody ServerInfoVo vo) throws Exception { ServerInfo info = serverInfoDao.getServerInfo(vo.getServer_id()); // 服务器信息不存在 if (info == null){ return 0; } // 修改服务器状态需要关闭自动开服功能 if (info.getStatus().equals(vo.getStatus()) && AutoServerManager.isOpen()){ return 3; } // 1. 修改服务器信息 serverInfoDao.updateServerInfo(vo); // 未运营 int notOperateState = ServerStatusEnum.NOT_OPERATE.getId(); // 2. 当前服务器状态是未运营状态时,会进行敏感数据修正 if (info.getStatusInt() == notOperateState){ // 2.1 修改跨服信息 updateGameGroupId(vo.getServer_id(),vo.getCrossGroupId()); // 2.2 修改开服时间 serverInfoDao.updateOpenServerTime(vo.getServer_id(),vo.getOpenTime()); // 重启服务器 GMHandler.sendGm(info.getServer_id(),"reloadserverconfig"); autoServerManager.restartServer2(info.getServer_id()); }else { updateGmGroupId(vo.getServer_id(),vo.getCrossGroupId()); } return 1; } /** * 批量修改服务器状态 * @param request * @return * @throws Exception */ @RequestMapping(value = "/serverListEdit", method = {RequestMethod.POST, RequestMethod.GET}) public @ResponseBody int serverListEdit(HttpServletRequest request) throws Exception { // f服务器列表 String serverId = request.getParameter("serverId"); String[] serverIds = serverId.split(","); // 跨服id String crossIdStr = request.getParameter("crossId"); String patch = "[-]?[0-9]+?"; boolean matches = patch.matches(crossIdStr); // 状态 String status = request.getParameter("status"); Map allServerMap = serverInfoDao.getAllServerMap(); for (String id : serverIds) { ServerInfo info = allServerMap.get(id); if (info == null){ LoginController.addQueue("无法在数据库内找到对应的服务器id,操作失败,服务器id:"+id); continue; } // 存在未运行状态的服务器不能批量修改 if (Integer.parseInt(info.getStatus()) == ServerStatusEnum.NOT_OPERATE.getId()){ LoginController.addQueue("服务器未处于《未运营》状态,无法修改,服务器id:"+id); continue; } // -5表示维护服务器并踢全部玩家下线,一般用于线上停服更新 if (status.equals("-5")){ serverInfoDao.updateServerInfo(id, "1"); GMHandler.sendGm(id,"kick 0"); }else if (!status.equals("-999")){ // 修改服务器信息 serverInfoDao.updateServerInfo(id, status); } // 修改跨服id,空或者非整数不做修改 if (matches){ updateGmGroupId(id,Integer.parseInt(crossIdStr)); } } return 1; } /** * 清库 * @return * @throws Exception */ @RequestMapping(value = "/cleanupServer", method = {RequestMethod.POST, RequestMethod.GET}) public @ResponseBody int cleanupServer(HttpServletRequest request) throws Exception { boolean power = commonManager.verifyPower(request, PowersEnum.CLEANUP_SERVER_PERMISSIONS); if (!power){ return 2; } String serverId = request.getParameter("serverId"); ServerInfo info = serverInfoDao.getServerInfo(serverId); // 服务器信息不存在 if (info == null){ return 0; } // 状态错误 if (info.getStatusInt() != ServerStatusEnum.NOT_OPERATE.getId()){ return 3; } // 2. 清库 ServerInfoVo serverInfoVo = createServerVo(info,1); TaskKit.scheduleWithFixedOne(()->autoServerManager.manualStartServer(serverInfoVo),0); return 1; } @RequestMapping(value = "/serverNumberInfo", method = {RequestMethod.POST, RequestMethod.GET}) public String serverNumberInfo(ModelMap map) throws Exception { List serverInfos = serverInfoDao.getAllServerInfo(); List serverInfoVos = new ArrayList<>(); int totalRegisterNum = 0; int totalOnlineNum = 0; for (ServerInfo serverInfo : serverInfos) { if (null == serverInfo.getServer_id()) { continue; } ServerInfoVo serverInfoVo = new ServerInfoVo(); // 服务器id serverInfoVo.setServer_id(serverInfo.getServer_id()); // 注册人数 long registerNum = serverInfoDao.getRegisterNum(serverInfo.getServer_id()); totalRegisterNum += registerNum; serverInfoVo.setRegisterNum(registerNum); // 在线人数 long onlineNum = serverInfoDao.getOnlineNum(serverInfo.getServer_id()); totalOnlineNum += onlineNum; serverInfoVo.setOnlineNum(onlineNum); serverInfoVos.add(serverInfoVo); } ServerInfoVo serverInfoVo = new ServerInfoVo(); serverInfoVo.setServer_id("总人数"); serverInfoVo.setRegisterNum(totalRegisterNum); serverInfoVo.setOnlineNum(totalOnlineNum); serverInfoVos.add(serverInfoVo); map.addAttribute("serverInfos", serverInfoVos); return "serverNumberInfo"; } /** * 添加服务器 * @param vo * @return * @throws Exception */ @RequestMapping(value = "/addServer", method = {RequestMethod.POST, RequestMethod.GET}) public @ResponseBody int addServer(@RequestBody ServerInfoVo vo) throws Exception { Map serverMap = serverInfoDao.getAllServerMap(); int count = vo.getCount(); // 批量添加,参数需要做特殊处理 if (count > 0){ // 需要修改的参数 int serverId = Integer.parseInt(vo.getServer_id()); // name模板,太初%d服 String named = vo.getName().split("#")[0]; // name数值,23 int nameNum = Integer.parseInt(vo.getName().split("#")[1]); int port = Integer.parseInt(vo.getPort()); int coreNum = Integer.parseInt(vo.getCoreName()); int crossGroupId = vo.getCrossGroupId(); for (int i = 0; i < count; i++) { int i1 = serverId + i; if (serverMap.get(String.valueOf(i1)) != null){ LOGGER.error("批量添加服务器,出现重复id:{}",i1); continue; } // 重新赋值 vo.set_id(i1); vo.setServer_id(String.valueOf(i1)); String name = named.replace("%d", String.valueOf(nameNum + i)); vo.setName(name); vo.setPort(String.valueOf(port+i)); vo.setCoreName("core"+(coreNum+i)); serverInfoDao.addServerInfo(vo); // 修改默认跨服id updateGameGroupId(vo.getServer_id(),crossGroupId); } // 单独添加 }else { ServerInfo info = serverMap.get(vo.getServer_id()); if (info != null){ return 0; } serverInfoDao.addServerInfo(vo); // 修改默认跨服id updateGameGroupId(vo.getServer_id(),vo.getCrossGroupId()); } return 1; } /** * 获取自动开服配置 * @param map * @return */ @RequestMapping(value = "/autoStartServerSetting", method = {RequestMethod.POST, RequestMethod.GET}) public String autoStartServerSetting(ModelMap map){ AutoServerSetting autoServerSetting = RedisUtil.getInstence().getMapValue(RedisUserKey.AUTO_START_SERVER_SETTING, "1", "1", AutoServerSetting.class, -1); if (autoServerSetting == null){ autoServerSetting = new AutoServerSetting(); } map.addAttribute("autoServerSetting", autoServerSetting); LOGGER.info("自动开服配置:{}",autoServerSetting.toString()); return "autoStartServerSetting"; } /** * 修改自动开服配置 * @param setting * @return */ @RequestMapping(value = "/updateAutoServerSetting", method = {RequestMethod.POST, RequestMethod.GET}) public @ResponseBody int updateAutoServerSetting(@RequestBody AutoServerSetting setting,HttpServletRequest request) throws Exception { boolean power = commonManager.verifyPower(request, PowersEnum.AUTO_START_SERVER_PERMISSIONS); if (!power){ return 2; } RedisUtil.getInstence().putMapEntry(RedisUserKey.AUTO_START_SERVER_SETTING, "1", "1", setting, -1); return 1; } /** * 重启服务器 * @param request * @return * @throws Exception */ @RequestMapping(value = "/restartServer", method = {RequestMethod.POST, RequestMethod.GET}) public @ResponseBody int restartServer(HttpServletRequest request) throws Exception { boolean power = commonManager.verifyPower(request, PowersEnum.RESTART_SERVER_PERMISSIONS); if (!power){ return 2; } String serverId = request.getParameter("serverId"); return autoServerManager.restartServer2(serverId); } /** * 端口监听状态处理 * @throws Exception */ private void portListenHandler(){ LOGGER.info("脚本执行,更新游戏服各端口状态:::"); long start = DateUtil.now(); // 脚本 String shell = "sh /data/jieling/port.sh"; Process exec = null; try { // 获取全部服务器列表 Map allServerMap = serverInfoDao.getAllServerMap(); //一台物理机可以配置多个游戏服 key:ip value:serverids HashMap> map = new HashMap<>(); for (ServerInfo value : allServerMap.values()) { List list = map.getOrDefault(value.getIp(), new ArrayList<>()); list.add(value.getServer_id()); map.put(value.getIp(),list); } ExpiryMap cacheMap = new ExpiryMap<>(); for (Map.Entry> entry : map.entrySet()) { String ip = entry.getKey(); List serverIds = entry.getValue(); // 游戏端口 exec = Runtime.getRuntime().exec(shell + " " + ip + " 160"); List gamePorts = AutoServerManager.readProcessOutput(exec); exec = null; // 支付端口 exec = Runtime.getRuntime().exec(shell + " " + ip + " 180"); List payPorts = AutoServerManager.readProcessOutput(exec); for (String serverId : serverIds) { // 端口缓存 int[] ports = cacheMap.getOrDefault(serverId,new int[2]); // 游戏端口校验 ServerInfo info = allServerMap.get(serverId); ports[0] = checkPort(gamePorts, info.getPort())?1:0; // 支付端口校验 String payPort = getPayPort(info.getPort()); ports[1] = checkPort(payPorts, payPort)?1:0; // 缓存处理,半小时 cacheMap.put(serverId,ports,DateUtil.ONE_HOUR/2); } } portStatusMap.clear(); portStatusMap = cacheMap; } catch (Exception e) { LoginController.addQueue("检查游戏端口状态报错:"+e.getMessage()); e.printStackTrace(); } finally { if (exec != null) { exec.destroy(); } } LOGGER.info("检测游戏端口耗时:{}",DateUtil.now()-start); } private String getPayPort(String gamePort){ return "180"+gamePort.substring(3); } /** * 检测端口 * @param strings * @param port * @return */ private boolean checkPort(List strings, String port){ ArrayList list = new ArrayList<>(); for (String string : strings) { // 1,用【:】分割 String[] split = string.split(":"); // 2,取最后一位,是端口号 String s = split[split.length - 1]; list.add(s); } return list.contains(port); } /** * 获取跨服服务器分组id * @param serverId * @return */ public static int getServerGroupId(String serverId){ Integer groupId = RedisUtil.getInstence().getMapValue(RedisUserKey.CROSS_SERVER_GROUP, "", serverId, Integer.class, -1); if (groupId == null){ groupId = 0; } return groupId; } /** * 获取游戏服跨服服务器分组id * @param serverId * @return */ public static int getGameServerGroupId(String serverId){ Integer groupId = RedisUtil.getInstence().getMapValue(RedisUserKey.SERVER_SPLIT_INFO, "", serverId, Integer.class, -1); if (groupId == null){ groupId = 0; } return groupId; } /** * 只会执行一次,同步游戏服跨服分组到gm,之后会以gm的为准 */ public static void oneRunServerGroup(){ Map map = RedisUtil.getInstence().getMap(RedisUserKey.CROSS_SERVER_GROUP + ":", Integer.class, -1); if (map == null || map.isEmpty()){ Map map1 = RedisUtil.getInstence().getMap(RedisUserKey.SERVER_SPLIT_INFO + ":", Integer.class, -1); RedisUtil.getInstence().putMap(RedisUserKey.CROSS_SERVER_GROUP,"",map1); LOGGER.info("同步跨服id完成"); } } /** * 更新游戏服跨服id * @param serverId * @param groupId */ public static void updateGameGroupId(String serverId, int groupId){ RedisUtil.getInstence().putMapEntry(RedisUserKey.SERVER_SPLIT_INFO,"",serverId,String.valueOf(groupId),-1); // 更新gm信息 updateGmGroupId(serverId,groupId); } /** * 更新gm跨服id * @param serverId * @param groupId */ public static void updateGmGroupId(String serverId, int groupId){ RedisUtil.getInstence().putMapEntry(RedisUserKey.CROSS_SERVER_GROUP,"",serverId,String.valueOf(groupId),-1); } }