package com.leaper.pm2java.service.impl; import com.leaper.pm2java.entity.AppServerEntity; import com.leaper.pm2java.entity.AppServerInfo; import com.leaper.pm2java.entity.WebSocketConn; import com.leaper.pm2java.entity.enums.ProcessStatus; import com.leaper.pm2java.service.Pm2JavaService; import com.leaper.pm2java.util.FileUtil; import com.leaper.pm2java.util.ProcessBuilderUtil; import com.leaper.pm2java.util.TimeUtil; import com.leaper.pm2java.websocket.WebSocket; import com.sun.management.OperatingSystemMXBean; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.Resource; import javax.xml.crypto.Data; import java.io.*; import java.lang.management.ManagementFactory; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.*; import java.util.stream.Collectors; @Service @Slf4j public class Pm2JavaServiceImpl implements Pm2JavaService { @Resource WebSocket webSocket; @Resource ProcessBuilderUtil processBuilderUtil; //现存的进程记录 public static Map processBuilderMap = new ConcurrentHashMap<>(); //记录的应用程序情况 public static Map appServerInfoRecordMap = new ConcurrentHashMap<>(); //创建一个固定线程个数的线程池 ExecutorService executor = Executors.newFixedThreadPool(10); //创建一个webSocket线程个数的线程池 ExecutorService executorWeb = Executors.newFixedThreadPool(10); public Map getAppServerInfoRecordMap() { return appServerInfoRecordMap; } @Override public void install(AppServerInfo appConfigEntity) { if (appConfigEntity.getArgsString() != null) { appConfigEntity.setArgs(appConfigEntity.getArgsString().split(",")); } FileUtil.saveFile(appConfigEntity); AppServerInfo appServerInfo = new AppServerInfo(); appServerInfo.setName(appConfigEntity.getName()); appServerInfo.setPath(appConfigEntity.getPath()); appServerInfo.setArgs(appConfigEntity.getArgs()); appServerInfo.setScript(appConfigEntity.getScript()); appServerInfo.setType(appConfigEntity.getType()); appServerInfo.setPort(appConfigEntity.getPort()); appServerInfo.setEnable(appConfigEntity.getEnable()); appServerInfoRecordMap.put(appServerInfo.getName(), appServerInfo); } @Override public void delete(AppServerEntity appConfigEntity, boolean permanently) { //停止服务 if (processBuilderMap.get(appConfigEntity.getName()) != null) { stop(appConfigEntity); } //删除内存记录 appServerInfoRecordMap.remove(appConfigEntity.getName()); if (permanently) { FileUtil.deleteFile(appConfigEntity); } } @Override public void update(AppServerEntity appConfigEntity) { FileUtil.saveFile(appConfigEntity); AppServerInfo appServerInfo = new AppServerInfo(); appServerInfo.setName(appConfigEntity.getName()); appServerInfo.setPath(appConfigEntity.getPath()); appServerInfo.setArgs(appConfigEntity.getArgs()); appServerInfo.setScript(appConfigEntity.getScript()); appServerInfo.setType(appConfigEntity.getType()); appServerInfo.setPort(appConfigEntity.getPort()); appServerInfo.setEnable(appConfigEntity.getEnable()); appServerInfoRecordMap.put(appServerInfo.getName(), appServerInfo); } @Override public void reset(AppServerEntity appConfigEntity) { } @Override public List select(AppServerInfo appServerInfo) { List list = appServerInfoRecordMap.keySet().stream() .peek(appName -> { if (processBuilderMap.get(appName) != null) { appServerInfoRecordMap.put(appName, searchNew(appServerInfoRecordMap.get(appName), appName)); } }) .filter(name -> {//名字搜索 if (appServerInfo != null && appServerInfo.getName() != null) { return name.contains(appServerInfo.getName()); } else return true; }) .filter(name -> { if (appServerInfo != null && appServerInfo.getOnOff() != null) { return appServerInfoRecordMap.get(name).getOnOff() == (appServerInfo.getOnOff()); } else return true; }) .map(name -> { return appServerInfoRecordMap.get(name); }) .collect(Collectors.toList()); return list; } @Override public List search() { List appServerInfos = new ArrayList<>(); List appServerEntities = FileUtil.readFile(); for (AppServerEntity appServerEntity : appServerEntities) { AppServerInfo appServerInfo = new AppServerInfo(); appServerInfo.setName(appServerEntity.getName()); appServerInfo.setPath(appServerEntity.getPath()); appServerInfo.setArgs(appServerEntity.getArgs()); appServerInfo.setScript(appServerEntity.getScript()); appServerInfo.setType(appServerEntity.getType()); appServerInfo.setEnable(appServerEntity.getEnable()); appServerInfo.setPort(appServerEntity.getPort()); appServerInfoRecordMap.put(appServerInfo.getName(), appServerInfo); } for (String appName : appServerInfoRecordMap.keySet()) { if (processBuilderMap.get(appName) != null) { appServerInfoRecordMap.get(appName).setOnOff(true); appServerInfos.add(searchNew(appServerInfoRecordMap.get(appName), appName)); } else { appServerInfoRecordMap.get(appName).setOnOff(false); appServerInfos.add(appServerInfoRecordMap.get(appName)); } } return appServerInfos; } public AppServerInfo searchNew(AppServerInfo appServerInfo, String appName) { appServerInfo.setOnOff(true); appServerInfo.setName(appName); appServerInfo.setSelectTime(LocalDateTime.now()); ProcessBuilder processBuilder = new ProcessBuilder("taskList", "/NH", "/V", "/FI", "\"PID eq " + processBuilderMap.get(appName).pid() + "\""); Process process = null; try { process = processBuilder.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "gbk")); String line = reader.readLine(); while (true) { // 排除首行和分隔线 if (line.startsWith("Image Name") || line.startsWith("=") || "".equals(line)) { line = reader.readLine(); System.out.println(line); } else { break; } } // 使用制表符分割每一列的值 String[] columns = line.split("\\s+"); if (columns.length < 9) { return appServerInfo; // 无效的行 } //映像名称 String imageName = columns[0].trim(); appServerInfo.setImageName(imageName); //会话名 String sessionName = columns[2].trim(); appServerInfo.setSessionName(sessionName); //会话# int sessionNumber = Integer.parseInt(columns[3].trim()); appServerInfo.setSessionNumber(sessionNumber); appServerInfo.setPid(processBuilderMap.get(appName).pid()); //内存 String ram = columns[4].trim(); appServerInfo.setRam(ram); //状态 String processStatus = columns[6].trim(); appServerInfo.setProcessStatus(ProcessStatus.fromValue(processStatus)); //cpu时间 long cpuTime = TimeUtil.convertTimeToSeconds(columns[8].trim()); appServerInfo.setCpuTime(cpuTime); System.out.println(appServerInfo); /*//计算cpu比例 if(appServerInfoRecordMap.get(appServerInfo.getName())!= null){ AppServerInfo appServerInfoOld = appServerInfoRecordMap.get(appServerInfo.getName()); Duration duration = Duration.between(appServerInfoOld.getStartTime(), appServerInfo.getStartTime()).abs(); long seconds = duration.getSeconds(); if(seconds <= 5){ } }*/ } catch (IOException e) { throw new RuntimeException(e); } appServerInfoRecordMap.put(appServerInfo.getName(), appServerInfo); return appServerInfo; } @Override public boolean status(long pid) { ProcessBuilder processBuilder = new ProcessBuilder("tasklist", "/fi", "PID eq " + pid); Process process = null; try { process = processBuilder.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); String line; while ((line = reader.readLine()) != null) { if (line.contains(" " + pid + " ")) { return true; } } } catch (IOException e) { throw new RuntimeException(e); } return false; } @Override public void remove(AppServerInfo appConfigEntity) { Integer number = appConfigEntity.getReNumber(); stop(appConfigEntity); start(appConfigEntity); log.info(appConfigEntity.getName()+"服务重启"); appServerInfoRecordMap.get(appConfigEntity.getName()).setReNumber(number++); } @Override public void start(AppServerEntity appConfigEntity) { if (processBuilderMap.get(appConfigEntity.getName()) != null) { return; } Future future = executor.submit(() -> { try { List cmd = new ArrayList(); cmd.add("cmd"); cmd.add("/c"); cmd.add(appConfigEntity.getScript()); if (null != appConfigEntity.getArgs() && appConfigEntity.getArgs().length != 0) { cmd.addAll(Arrays.asList(appConfigEntity.getArgs())); } // 创建 ProcessBuilder 对象,并设置要执行的命令 ProcessBuilder pb = new ProcessBuilder(cmd); if(appConfigEntity.getPath()!= null &&!"".equals(appConfigEntity.getPath())){ pb.directory(new File(appConfigEntity.getPath())); } // 将标准输出和错误输出合并 pb.redirectErrorStream(true); pb.environment().put("LANG", "zh_CN.UTF-8"); // 启动命令并获取 Process 对象 Process process = pb.start(); processBuilderMap.put(appConfigEntity.getName(), process); appServerInfoRecordMap.get(appConfigEntity.getName()).setOnOff(true); appServerInfoRecordMap.get(appConfigEntity.getName()).setStartTime(LocalDateTime.now()); appServerInfoRecordMap.get(appConfigEntity.getName()).setSelectTime(LocalDateTime.now()); log.info("{}服务启动", appConfigEntity.getName()); processBuilderUtil.getProcessLogs(processBuilderMap.get(appConfigEntity.getName()),appConfigEntity.getName()); // 等待命令执行完成 int exitCode = process.waitFor(); System.out.println(); log.info(appConfigEntity.getName()+"服务退出,命令退出码:" + exitCode); processBuilderMap.remove(appConfigEntity.getName()); if(appServerInfoRecordMap.get(appConfigEntity.getName()).getOnOff() && appConfigEntity.getEnableRestart()){ start(appConfigEntity); appServerInfoRecordMap.get(appConfigEntity.getName()).setReNumber(appServerInfoRecordMap.get(appConfigEntity.getName()).getReNumber()+1); }else { appServerInfoRecordMap.get(appConfigEntity.getName()).setReNumber(0); } appServerInfoRecordMap.get(appConfigEntity.getName()).setOnOff(false); appServerInfoRecordMap.get(appConfigEntity.getName()).setPid(null); appServerInfoRecordMap.get(appConfigEntity.getName()).setStartTime(null); appServerInfoRecordMap.get(appConfigEntity.getName()).setRam(null); } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } finally { if (processBuilderMap.get(appConfigEntity.getName()) != null) { processBuilderMap.get(appConfigEntity.getName()).destroyForcibly(); } } }); } public void stopByName(String name) { stop(appServerInfoRecordMap.get(name)); } @Override public void stop(AppServerEntity appConfigEntity) { // 创建 ProcessBuilder 对象,并设置要执行的命令 ProcessBuilder pb = new ProcessBuilder("taskkill", "/f", "/t", "/pid", String.valueOf(processBuilderMap.get(appConfigEntity.getName()).pid())); // 将标准输出和错误输出合并 pb.redirectErrorStream(true); pb.environment().put("LANG", "zh_CN.UTF-8"); Process process = null; try { process = pb.start(); appServerInfoRecordMap.get(appConfigEntity.getName()).setOnOff(false); // 等待命令执行完成 int exitCode = process.waitFor(); System.out.println("命令退出码:" + exitCode); log.info("{}服务停止", appConfigEntity.getName()); } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Override public void sendLog(WebSocketConn webSocketConn) { executorWeb.submit(() -> { if (webSocket.getUserIds().contains(webSocketConn.getUid())) { Process process = processBuilderMap.get(webSocketConn.getAppName()); // 获取命令的输出流 InputStream inputStream = process.getInputStream(); try { // 读取输出流内容 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "gbk")); String line; StringBuilder output = new StringBuilder(); while (true) { if ((line = reader.readLine()) == null) break; webSocket.sendOneMessage(webSocketConn.getUid(), new String(line.getBytes(), StandardCharsets.UTF_8)); } } catch (IOException e) { throw new RuntimeException(e); } } }); } }