miduo_gm/src/main/java/com/jmfy/controller/ServerInfoController.java

630 lines
23 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<String,CServerOpenTime> serverStatus = new ExpiryMap<>();
/**
* 游戏服端口状态
* key: 服务器id
* value [0]:游戏服端口状态, [1]:支付端口状态
*/
private static ExpiryMap<String,int[]> 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<ServerInfoVo> serverInfoVos = new ArrayList<>();
List<ServerInfo> 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<ServerInfo> 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<String, ServerInfo> 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<String, ServerInfo> 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<ServerInfo> serverInfos = serverInfoDao.getAllServerInfo();
List<ServerInfoVo> 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<String, ServerInfo> 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<String, ServerInfo> allServerMap = serverInfoDao.getAllServerMap();
//一台物理机可以配置多个游戏服 keyip valueserverids
HashMap<String, List<String>> map = new HashMap<>();
for (ServerInfo value : allServerMap.values()) {
List<String> list = map.getOrDefault(value.getIp(), new ArrayList<>());
list.add(value.getServer_id());
map.put(value.getIp(),list);
}
ExpiryMap<String,int[]> cacheMap = new ExpiryMap<>();
for (Map.Entry<String, List<String>> entry : map.entrySet()) {
String ip = entry.getKey();
List<String> serverIds = entry.getValue();
// 游戏端口
exec = Runtime.getRuntime().exec(shell + " " + ip + " 160");
List<String> gamePorts = AutoServerManager.readProcessOutput(exec);
exec = null;
// 支付端口
exec = Runtime.getRuntime().exec(shell + " " + ip + " 180");
List<String> 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<String> strings, String port){
ArrayList<String> 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<String, Integer> map = RedisUtil.getInstence().getMap(RedisUserKey.CROSS_SERVER_GROUP + ":", Integer.class, -1);
if (map == null || map.isEmpty()){
Map<String, Integer> 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);
}
}