You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

364 lines
15 KiB
Java

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<String, Process> processBuilderMap = new ConcurrentHashMap<>();
//记录的应用程序情况
public static Map<String, AppServerInfo> appServerInfoRecordMap = new ConcurrentHashMap<>();
//创建一个固定线程个数的线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
//创建一个webSocket线程个数的线程池
ExecutorService executorWeb = Executors.newFixedThreadPool(10);
public Map<String, AppServerInfo> 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<AppServerInfo> select(AppServerInfo appServerInfo) {
List<AppServerInfo> 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<AppServerInfo> search() {
List<AppServerInfo> appServerInfos = new ArrayList<>();
List<AppServerEntity> 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<String> cmd = new ArrayList<String>();
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);
}
}
});
}
}