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
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);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|