system monitor added
This commit is contained in:
parent
371a696fce
commit
33d61b1805
46
app/pom.xml
46
app/pom.xml
@ -78,16 +78,16 @@
|
|||||||
<artifactId>jsch</artifactId>
|
<artifactId>jsch</artifactId>
|
||||||
<version>0.1.54</version>
|
<version>0.1.54</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- <dependency> -->
|
<dependency>
|
||||||
<!-- <groupId>net.java.dev.jna</groupId> -->
|
<groupId>net.java.dev.jna</groupId>
|
||||||
<!-- <artifactId>jna-platform</artifactId> -->
|
<artifactId>jna-platform</artifactId>
|
||||||
<!-- <version>5.3.1</version> -->
|
<version>5.3.1</version>
|
||||||
<!-- </dependency> -->
|
</dependency>
|
||||||
<!-- <dependency> -->
|
<dependency>
|
||||||
<!-- <groupId>net.java.dev.jna</groupId> -->
|
<groupId>net.java.dev.jna</groupId>
|
||||||
<!-- <artifactId>jna</artifactId> -->
|
<artifactId>jna</artifactId>
|
||||||
<!-- <version>5.3.1</version> -->
|
<version>5.3.1</version>
|
||||||
<!-- </dependency> -->
|
</dependency>
|
||||||
<!-- <dependency> -->
|
<!-- <dependency> -->
|
||||||
<!-- <groupId>log4j</groupId> -->
|
<!-- <groupId>log4j</groupId> -->
|
||||||
<!-- <artifactId>log4j</artifactId> -->
|
<!-- <artifactId>log4j</artifactId> -->
|
||||||
@ -128,6 +128,32 @@
|
|||||||
<version>1.21</version>
|
<version>1.21</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.oshi</groupId>
|
||||||
|
<artifactId>oshi-dist</artifactId>
|
||||||
|
<version>3.13.3</version>
|
||||||
|
<type>pom</type>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.oshi</groupId>
|
||||||
|
<artifactId>oshi-core</artifactId>
|
||||||
|
<version>3.13.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.oshi</groupId>
|
||||||
|
<artifactId>oshi-json</artifactId>
|
||||||
|
<version>3.13.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.oshi</groupId>
|
||||||
|
<artifactId>oshi-parent</artifactId>
|
||||||
|
<version>3.13.3</version>
|
||||||
|
<type>pom</type>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
@ -36,6 +36,9 @@ import cloudshell.app.files.PosixPermission;
|
|||||||
import cloudshell.app.files.copy.FileCopyProgressResponse;
|
import cloudshell.app.files.copy.FileCopyProgressResponse;
|
||||||
import cloudshell.app.files.copy.FileCopyRequest;
|
import cloudshell.app.files.copy.FileCopyRequest;
|
||||||
import cloudshell.app.files.search.SearchResult;
|
import cloudshell.app.files.search.SearchResult;
|
||||||
|
import cloudshell.app.health.ProcessInfo;
|
||||||
|
import cloudshell.app.health.SystemHealthMonitor;
|
||||||
|
import cloudshell.app.health.SystemStats;
|
||||||
import cloudshell.app.terminal.PtySession;
|
import cloudshell.app.terminal.PtySession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,6 +59,9 @@ public class AppController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private BCryptPasswordEncoder passwordEncoder;
|
private BCryptPasswordEncoder passwordEncoder;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private SystemHealthMonitor healthMon;
|
||||||
|
|
||||||
@PostMapping("/app/terminal/{appId}/resize")
|
@PostMapping("/app/terminal/{appId}/resize")
|
||||||
public void resizePty(@PathVariable String appId,
|
public void resizePty(@PathVariable String appId,
|
||||||
@RequestBody Map<String, Integer> body) {
|
@RequestBody Map<String, Integer> body) {
|
||||||
@ -314,4 +320,22 @@ public class AppController {
|
|||||||
Files.createFile(path);
|
Files.createFile(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping("/app/sys/stats")
|
||||||
|
public SystemStats getStats() {
|
||||||
|
return this.healthMon.getStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("/app/sys/procs")
|
||||||
|
public List<ProcessInfo> getProcessList() {
|
||||||
|
return this.healthMon.getProcessList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping("/app/sys/procs")
|
||||||
|
public Map<String, Boolean> killProcesses(
|
||||||
|
@RequestBody List<Integer> pidList) {
|
||||||
|
Map<String, Boolean> map = new HashMap<>();
|
||||||
|
map.put("success", this.healthMon.killProcess(pidList));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ public class FileTypeDetector {
|
|||||||
return tika.detect(file);
|
return tika.detect(file);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO Auto-generated catch block
|
// TODO Auto-generated catch block
|
||||||
e.printStackTrace();
|
|
||||||
return "application/octet-stream";
|
return "application/octet-stream";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
155
app/src/main/java/cloudshell/app/health/ProcessInfo.java
Normal file
155
app/src/main/java/cloudshell/app/health/ProcessInfo.java
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package cloudshell.app.health;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author subhro
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class ProcessInfo {
|
||||||
|
private String name, command, user, state;
|
||||||
|
private int pid, priority;
|
||||||
|
private double cpuUsage, memoryUsage, vmUsage;
|
||||||
|
private long startTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the name
|
||||||
|
*/
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param name the name to set
|
||||||
|
*/
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the command
|
||||||
|
*/
|
||||||
|
public String getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param command the command to set
|
||||||
|
*/
|
||||||
|
public void setCommand(String command) {
|
||||||
|
this.command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the user
|
||||||
|
*/
|
||||||
|
public String getUser() {
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param user the user to set
|
||||||
|
*/
|
||||||
|
public void setUser(String user) {
|
||||||
|
this.user = user;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the state
|
||||||
|
*/
|
||||||
|
public String getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param state the state to set
|
||||||
|
*/
|
||||||
|
public void setState(String state) {
|
||||||
|
this.state = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the pid
|
||||||
|
*/
|
||||||
|
public int getPid() {
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param pid the pid to set
|
||||||
|
*/
|
||||||
|
public void setPid(int pid) {
|
||||||
|
this.pid = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the cpuUsage
|
||||||
|
*/
|
||||||
|
public double getCpuUsage() {
|
||||||
|
return cpuUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cpuUsage the cpuUsage to set
|
||||||
|
*/
|
||||||
|
public void setCpuUsage(double cpuUsage) {
|
||||||
|
this.cpuUsage = cpuUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the memoryUsage
|
||||||
|
*/
|
||||||
|
public double getMemoryUsage() {
|
||||||
|
return memoryUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param memoryUsage the memoryUsage to set
|
||||||
|
*/
|
||||||
|
public void setMemoryUsage(double memoryUsage) {
|
||||||
|
this.memoryUsage = memoryUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the vmUsage
|
||||||
|
*/
|
||||||
|
public double getVmUsage() {
|
||||||
|
return vmUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param vmUsage the vmUsage to set
|
||||||
|
*/
|
||||||
|
public void setVmUsage(double vmUsage) {
|
||||||
|
this.vmUsage = vmUsage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the startTime
|
||||||
|
*/
|
||||||
|
public long getStartTime() {
|
||||||
|
return startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param startTime the startTime to set
|
||||||
|
*/
|
||||||
|
public void setStartTime(long startTime) {
|
||||||
|
this.startTime = startTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the priority
|
||||||
|
*/
|
||||||
|
public int getPriority() {
|
||||||
|
return priority;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param priority the priority to set
|
||||||
|
*/
|
||||||
|
public void setPriority(int priority) {
|
||||||
|
this.priority = priority;
|
||||||
|
}
|
||||||
|
}
|
130
app/src/main/java/cloudshell/app/health/SystemHealthMonitor.java
Normal file
130
app/src/main/java/cloudshell/app/health/SystemHealthMonitor.java
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package cloudshell.app.health;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import oshi.SystemInfo;
|
||||||
|
import oshi.hardware.CentralProcessor;
|
||||||
|
import oshi.hardware.GlobalMemory;
|
||||||
|
import oshi.hardware.HardwareAbstractionLayer;
|
||||||
|
import oshi.software.os.OSProcess;
|
||||||
|
import oshi.software.os.OperatingSystem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author subhro
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class SystemHealthMonitor {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private CentralProcessor processor;
|
||||||
|
private GlobalMemory memory;
|
||||||
|
private OperatingSystem os;
|
||||||
|
private boolean isWindows;
|
||||||
|
|
||||||
|
private SystemInfo si;
|
||||||
|
|
||||||
|
public SystemHealthMonitor() {
|
||||||
|
si = new SystemInfo();
|
||||||
|
HardwareAbstractionLayer hal = si.getHardware();
|
||||||
|
os = si.getOperatingSystem();
|
||||||
|
processor = hal.getProcessor();
|
||||||
|
memory = hal.getMemory();
|
||||||
|
processor.getSystemCpuLoadBetweenTicks();
|
||||||
|
isWindows = System.getProperty("os.name").toLowerCase()
|
||||||
|
.contains("windows");
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized SystemStats getStats() {
|
||||||
|
SystemStats stats = new SystemStats();
|
||||||
|
double cpuUsed = processor.getSystemCpuLoadBetweenTicks() * 100;
|
||||||
|
|
||||||
|
stats.setCpuUsed(cpuUsed);
|
||||||
|
stats.setCpuFree(100 - cpuUsed);
|
||||||
|
|
||||||
|
long avail = memory.getAvailable();
|
||||||
|
long total = memory.getTotal();
|
||||||
|
if (total > 0) {
|
||||||
|
double memoryUsed = ((total - avail) * 100) / total;
|
||||||
|
stats.setMemoryUsed(memoryUsed);
|
||||||
|
stats.setMemoryFree(100 - memoryUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
File f = new File("/");
|
||||||
|
long totalDiskSpace = f.getTotalSpace();
|
||||||
|
long freeDiskSpace = f.getFreeSpace();
|
||||||
|
if (totalDiskSpace > 0) {
|
||||||
|
double diskUsed = ((totalDiskSpace - freeDiskSpace) * 100)
|
||||||
|
/ totalDiskSpace;
|
||||||
|
stats.setDiskUsed(diskUsed);
|
||||||
|
stats.setDiskFree(100 - diskUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
long totalSwap = memory.getSwapTotal();
|
||||||
|
long usedSwap = memory.getSwapUsed();
|
||||||
|
if (totalSwap > 0) {
|
||||||
|
double swapUsed = usedSwap * 100 / totalSwap;
|
||||||
|
stats.setSwapUsed(swapUsed);
|
||||||
|
stats.setSwapFree(100 - swapUsed);
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized List<ProcessInfo> getProcessList() {
|
||||||
|
OSProcess[] procs = os.getProcesses(0, null, false);
|
||||||
|
List<ProcessInfo> list = new ArrayList<>();
|
||||||
|
if (procs != null && procs.length > 0) {
|
||||||
|
for (OSProcess proc : procs) {
|
||||||
|
ProcessInfo info = new ProcessInfo();
|
||||||
|
info.setPid(proc.getProcessID());
|
||||||
|
info.setName(proc.getName());
|
||||||
|
info.setCommand(proc.getCommandLine());
|
||||||
|
info.setCpuUsage(proc.calculateCpuPercent());
|
||||||
|
info.setMemoryUsage(proc.getResidentSetSize());
|
||||||
|
info.setVmUsage(proc.getVirtualSize());
|
||||||
|
info.setState(proc.getState().toString());
|
||||||
|
info.setStartTime(proc.getStartTime());
|
||||||
|
info.setUser(proc.getUser());
|
||||||
|
info.setPriority(proc.getPriority());
|
||||||
|
list.add(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean killProcess(int pid) {
|
||||||
|
ProcessBuilder pb = new ProcessBuilder(
|
||||||
|
isWindows ? Arrays.asList("taskkill", "/pid", pid + "", "/f")
|
||||||
|
: Arrays.asList("kill", "-9", pid + ""));
|
||||||
|
try {
|
||||||
|
Process proc = pb.start();
|
||||||
|
int ret = proc.waitFor();
|
||||||
|
return ret == 0;
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean killProcess(List<Integer> pidList) {
|
||||||
|
boolean success = true;
|
||||||
|
for (Integer pid : pidList) {
|
||||||
|
if (success) {
|
||||||
|
success = killProcess(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
}
|
125
app/src/main/java/cloudshell/app/health/SystemStats.java
Normal file
125
app/src/main/java/cloudshell/app/health/SystemStats.java
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package cloudshell.app.health;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author subhro
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SystemStats {
|
||||||
|
private double cpuUsed = -1, cpuFree = -1, memoryUsed = -1, memoryFree = -1,
|
||||||
|
swapUsed = -1, swapFree = -1, diskUsed = -1, diskFree = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the cpuUsed
|
||||||
|
*/
|
||||||
|
public double getCpuUsed() {
|
||||||
|
return cpuUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cpuUsed the cpuUsed to set
|
||||||
|
*/
|
||||||
|
public void setCpuUsed(double cpuUsed) {
|
||||||
|
this.cpuUsed = cpuUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the cpuFree
|
||||||
|
*/
|
||||||
|
public double getCpuFree() {
|
||||||
|
return cpuFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param cpuFree the cpuFree to set
|
||||||
|
*/
|
||||||
|
public void setCpuFree(double cpuFree) {
|
||||||
|
this.cpuFree = cpuFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the memoryUsed
|
||||||
|
*/
|
||||||
|
public double getMemoryUsed() {
|
||||||
|
return memoryUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param memoryUsed the memoryUsed to set
|
||||||
|
*/
|
||||||
|
public void setMemoryUsed(double memoryUsed) {
|
||||||
|
this.memoryUsed = memoryUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the memoryFree
|
||||||
|
*/
|
||||||
|
public double getMemoryFree() {
|
||||||
|
return memoryFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param memoryFree the memoryFree to set
|
||||||
|
*/
|
||||||
|
public void setMemoryFree(double memoryFree) {
|
||||||
|
this.memoryFree = memoryFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the swapUsed
|
||||||
|
*/
|
||||||
|
public double getSwapUsed() {
|
||||||
|
return swapUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param swapUsed the swapUsed to set
|
||||||
|
*/
|
||||||
|
public void setSwapUsed(double swapUsed) {
|
||||||
|
this.swapUsed = swapUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the swapFree
|
||||||
|
*/
|
||||||
|
public double getSwapFree() {
|
||||||
|
return swapFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param swapFree the swapFree to set
|
||||||
|
*/
|
||||||
|
public void setSwapFree(double swapFree) {
|
||||||
|
this.swapFree = swapFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the diskUsed
|
||||||
|
*/
|
||||||
|
public double getDiskUsed() {
|
||||||
|
return diskUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param diskUsed the diskUsed to set
|
||||||
|
*/
|
||||||
|
public void setDiskUsed(double diskUsed) {
|
||||||
|
this.diskUsed = diskUsed;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the diskFree
|
||||||
|
*/
|
||||||
|
public double getDiskFree() {
|
||||||
|
return diskFree;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param diskFree the diskFree to set
|
||||||
|
*/
|
||||||
|
public void setDiskFree(double diskFree) {
|
||||||
|
this.diskFree = diskFree;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package cloudshell.app.terminal;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author subhro
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public interface PtyProcessPipe {
|
||||||
|
public int read(byte[] b) throws Exception;
|
||||||
|
|
||||||
|
public void write(byte[] b, int off, int len) throws Exception;
|
||||||
|
|
||||||
|
public void resizePty(int col, int row, int wp, int hp);
|
||||||
|
}
|
201
app/src/main/java/cloudshell/app/terminal/SshPtyProcessPipe.java
Normal file
201
app/src/main/java/cloudshell/app/terminal/SshPtyProcessPipe.java
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package cloudshell.app.terminal;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PipedInputStream;
|
||||||
|
import java.io.PipedOutputStream;
|
||||||
|
import java.io.PipedReader;
|
||||||
|
import java.io.PipedWriter;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
|
import com.jcraft.jsch.ChannelShell;
|
||||||
|
import com.jcraft.jsch.JSch;
|
||||||
|
import com.jcraft.jsch.Session;
|
||||||
|
import com.jcraft.jsch.UserInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author subhro
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class SshPtyProcessPipe implements PtyProcessPipe, UserInfo {
|
||||||
|
|
||||||
|
private PipedInputStream _in, in;
|
||||||
|
private PipedOutputStream _out, out;
|
||||||
|
private String hostName, keyFile, user;
|
||||||
|
private int port;
|
||||||
|
private JSch jsch;
|
||||||
|
private Session session;
|
||||||
|
private ChannelShell shell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IOException
|
||||||
|
* @throws UnsupportedEncodingException
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public SshPtyProcessPipe() {
|
||||||
|
hostName = "192.168.56.106";
|
||||||
|
port = 22;
|
||||||
|
user = "subhro";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void start() {
|
||||||
|
try {
|
||||||
|
_out = new PipedOutputStream();
|
||||||
|
in = new PipedInputStream(_out, 1);
|
||||||
|
_in = new PipedInputStream(1);
|
||||||
|
out = new PipedOutputStream(_in);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
new Thread(() -> {
|
||||||
|
try {
|
||||||
|
_start();
|
||||||
|
} catch (Exception e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void _start() throws Exception {
|
||||||
|
|
||||||
|
jsch = new JSch();
|
||||||
|
JSch.setConfig("MaxAuthTries", "5");
|
||||||
|
|
||||||
|
if (keyFile != null && keyFile.length() > 0) {
|
||||||
|
jsch.addIdentity(keyFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
session = jsch.getSession(user, hostName, port);
|
||||||
|
|
||||||
|
session.setUserInfo(this);
|
||||||
|
// session.setConfig("StrictHostKeyChecking", "no");
|
||||||
|
session.setConfig("PreferredAuthentications",
|
||||||
|
"publickey,keyboard-interactive,password");
|
||||||
|
|
||||||
|
System.out.println("Before connect");
|
||||||
|
|
||||||
|
session.connect();
|
||||||
|
|
||||||
|
System.out.println("Client version: " + session.getClientVersion());
|
||||||
|
System.out.println("Server host: " + session.getHost());
|
||||||
|
System.out.println("Server version: " + session.getServerVersion());
|
||||||
|
System.out.println(
|
||||||
|
"Hostkey: " + session.getHostKey().getFingerPrint(jsch));
|
||||||
|
|
||||||
|
shell = (ChannelShell) session.openChannel("shell");
|
||||||
|
shell.setEnv("TERM", "xterm");
|
||||||
|
|
||||||
|
shell.setInputStream(in);
|
||||||
|
shell.setOutputStream(out);
|
||||||
|
|
||||||
|
shell.connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void resizePty(int col, int row, int wp, int hp) {
|
||||||
|
shell.setPtySize(col, row, wp, hp);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String readLine() throws IOException {
|
||||||
|
System.out.println("Attempt readline");
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
while (true) {
|
||||||
|
int ch = in.read();
|
||||||
|
System.out.println("char: " + ch);
|
||||||
|
if (ch == -1 || ch == '\n'|| ch == '\r')
|
||||||
|
break;
|
||||||
|
sb.append((char) ch);
|
||||||
|
}
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassphrase() {
|
||||||
|
try {
|
||||||
|
return readLine();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getPassword() {
|
||||||
|
try {
|
||||||
|
String pass = readLine();
|
||||||
|
System.out.println("Paww: " + pass);
|
||||||
|
return pass;
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean promptPassword(String message) {
|
||||||
|
System.out.println("prompt password: " + message);
|
||||||
|
try {
|
||||||
|
out.write(message.getBytes("utf-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean promptPassphrase(String message) {
|
||||||
|
try {
|
||||||
|
out.write(message.getBytes("utf-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean promptYesNo(String message) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void showMessage(String message) {
|
||||||
|
System.out.println("prompt messae: " + message);
|
||||||
|
try {
|
||||||
|
out.write(message.getBytes("utf-8"));
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// TODO Auto-generated catch block
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] b) throws Exception {
|
||||||
|
return _in.read(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) throws Exception {
|
||||||
|
this._out.write(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -20,13 +20,16 @@
|
|||||||
"@angular/platform-browser-dynamic": "~7.2.0",
|
"@angular/platform-browser-dynamic": "~7.2.0",
|
||||||
"@angular/router": "~7.2.0",
|
"@angular/router": "~7.2.0",
|
||||||
"@ng-bootstrap/ng-bootstrap": "^4.2.0",
|
"@ng-bootstrap/ng-bootstrap": "^4.2.0",
|
||||||
|
"@swimlane/ngx-charts": "^12.0.1",
|
||||||
"bootstrap": "^4.3.1",
|
"bootstrap": "^4.3.1",
|
||||||
|
"chart.js": "^2.8.0",
|
||||||
"core-js": "^2.5.4",
|
"core-js": "^2.5.4",
|
||||||
"font-awesome": "^4.7.0",
|
"font-awesome": "^4.7.0",
|
||||||
"ng2-ace-editor": "^0.3.9",
|
"ng2-ace-editor": "^0.3.9",
|
||||||
|
"ng2-charts": "^2.2.3",
|
||||||
"rxjs": "~6.3.3",
|
"rxjs": "~6.3.3",
|
||||||
"tslib": "^1.9.0",
|
"tslib": "^1.9.0",
|
||||||
"xterm": "^3.13.2",
|
"xterm": "^3.14.5",
|
||||||
"zone.js": "~0.8.26"
|
"zone.js": "~0.8.26"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
import { BrowserModule } from '@angular/platform-browser';
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
import { HttpClientModule } from '@angular/common/http';
|
import { HttpClientModule } from '@angular/common/http';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
|
|
||||||
|
import {NgxChartsModule} from '@swimlane/ngx-charts';
|
||||||
|
import { ChartsModule } from 'ng2-charts';
|
||||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
|
||||||
import { AppRoutingModule } from './app-routing.module';
|
import { AppRoutingModule } from './app-routing.module';
|
||||||
@ -54,7 +57,10 @@ import { NewItemComponent } from './home/files/browser/new-item/new-item.compone
|
|||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
NgbModule,
|
NgbModule,
|
||||||
HttpClientModule
|
HttpClientModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
NgxChartsModule,
|
||||||
|
ChartsModule
|
||||||
],
|
],
|
||||||
providers: [httpInterceptorProviders],
|
providers: [httpInterceptorProviders],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
@ -78,7 +78,7 @@ export class DataService {
|
|||||||
|
|
||||||
currentViewChanger = new Subject<string>();
|
currentViewChanger = new Subject<string>();
|
||||||
|
|
||||||
viewTextRequests=new Subject<string>();
|
viewTextRequests = new Subject<string>();
|
||||||
|
|
||||||
terminalSession: TerminalSession;
|
terminalSession: TerminalSession;
|
||||||
|
|
||||||
@ -404,4 +404,16 @@ export class DataService {
|
|||||||
return this.http.get<any>(environment.BASE_URL + "token/temp");
|
return this.http.get<any>(environment.BASE_URL + "token/temp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getSystemStats(): Observable<any> {
|
||||||
|
return this.http.get<any>(environment.BASE_URL + "app/sys/stats");
|
||||||
|
}
|
||||||
|
|
||||||
|
getProcessList(): Observable<any[]> {
|
||||||
|
return this.http.get<any[]>(environment.BASE_URL + "app/sys/procs");
|
||||||
|
}
|
||||||
|
|
||||||
|
killProcesses(pids: any[]): Observable<any> {
|
||||||
|
return this.http.post<any>(environment.BASE_URL + "app/sys/procs", pids);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -20,22 +20,31 @@
|
|||||||
Settings
|
Settings
|
||||||
</a> -->
|
</a> -->
|
||||||
|
|
||||||
<span style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
(click)="view=null" [ngClass]="{'active-link': view==null}">
|
(click)="view=null" [ngClass]="{'active-link': view==null}">
|
||||||
Files
|
Files
|
||||||
</span>
|
</span>
|
||||||
<span style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
(click)="view='editor'" [ngClass]="{'active-link': view=='editor'}">
|
(click)="view='editor'" [ngClass]="{'active-link': view=='editor'}">
|
||||||
Editor
|
Editor
|
||||||
</span>
|
</span>
|
||||||
<span style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
(click)="view='search'" [ngClass]="{'active-link': view=='search'}">
|
(click)="view='search'" [ngClass]="{'active-link': view=='search'}">
|
||||||
Search
|
Search
|
||||||
</span>
|
</span>
|
||||||
<span style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
(click)="view='settings'" [ngClass]="{'active-link': view=='settings'}">
|
(click)="view='settings'" [ngClass]="{'active-link': view=='settings'}">
|
||||||
Settings
|
Settings
|
||||||
</span>
|
</span>
|
||||||
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
|
(click)="view='sysmon'" [ngClass]="{'active-link': view=='sysmon'}">
|
||||||
|
Monitoring
|
||||||
|
</span>
|
||||||
|
|
||||||
<!-- <span *ngFor="let tab of tabs; let i=index"
|
<!-- <span *ngFor="let tab of tabs; let i=index"
|
||||||
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center;"
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center;"
|
||||||
@ -50,22 +59,31 @@
|
|||||||
<div style="flex: 1; line-height: 55px; color: gray; font-size: 22px;">
|
<div style="flex: 1; line-height: 55px; color: gray; font-size: 22px;">
|
||||||
<span><i class="fa fa-terminal" aria-hidden="true"></i></span>
|
<span><i class="fa fa-terminal" aria-hidden="true"></i></span>
|
||||||
</div>
|
</div>
|
||||||
<span style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
(click)="view=null" [ngClass]="{'active-link': view==null}">
|
(click)="view=null" [ngClass]="{'active-link': view==null}">
|
||||||
<i class="fa fa-folder"></i>
|
<i class="fa fa-folder"></i>
|
||||||
</span>
|
</span>
|
||||||
<span style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
(click)="view='editor'" [ngClass]="{'active-link': view=='editor'}">
|
(click)="view='editor'" [ngClass]="{'active-link': view=='editor'}">
|
||||||
<i class="fa fa-file"></i>
|
<i class="fa fa-file"></i>
|
||||||
</span>
|
</span>
|
||||||
<span style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
(click)="view='search'" [ngClass]="{'active-link': view=='search'}">
|
(click)="view='search'" [ngClass]="{'active-link': view=='search'}">
|
||||||
<i class="fa fa-search"></i>
|
<i class="fa fa-search"></i>
|
||||||
</span>
|
</span>
|
||||||
<span style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
(click)="view='settings'" [ngClass]="{'active-link': view=='settings'}">
|
(click)="view='settings'" [ngClass]="{'active-link': view=='settings'}">
|
||||||
<i class="fa fa-cogs"></i>
|
<i class="fa fa-cogs"></i>
|
||||||
</span>
|
</span>
|
||||||
|
<span
|
||||||
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center; text-decoration: none;"
|
||||||
|
(click)="view='sysmon'" [ngClass]="{'active-link': view=='sysmon'}">
|
||||||
|
<i class="fa fa-bar-chart" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
|
||||||
<!-- <span *ngFor="let tab of tabs; let i=index"
|
<!-- <span *ngFor="let tab of tabs; let i=index"
|
||||||
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center;"
|
style="cursor: pointer; line-height: 55px; padding-left: 15px; padding-right: 15px; color: gray; text-align: center;"
|
||||||
@ -76,11 +94,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="router-wrapper">
|
<div class="router-wrapper">
|
||||||
<app-editor [style.display]="view=='editor'?'block':'none'" ></app-editor>
|
<app-monitoring *ngIf="view=='sysmon'"></app-monitoring>
|
||||||
<app-search [style.display]="view=='search'?'block':'none'" ></app-search>
|
<app-editor [style.display]="view=='editor'?'block':'none'"></app-editor>
|
||||||
<app-settings [style.display]="view=='settings'?'block':'none'" ></app-settings>
|
<app-search [style.display]="view=='search'?'block':'none'"></app-search>
|
||||||
<div style="width: 100vw; height: calc(100vh - 55px);" [style.display]="view?'none':'block'" >
|
<app-settings [style.display]="view=='settings'?'block':'none'"></app-settings>
|
||||||
<app-files (viewChanged)="view=$event"></app-files>
|
<div style="width: 100vw; height: calc(100vh - 55px);" [style.display]="view?'none':'block'">
|
||||||
|
<app-files (viewChanged)="view=$event"></app-files>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <router-outlet></router-outlet> -->
|
<!-- <router-outlet></router-outlet> -->
|
||||||
@ -130,14 +149,16 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="position: fixed; width: 100vw; height: 100vh; z-index: 300; left: 0px; top: 0px; display: flex; flex-direction: column; background: rgb(40,40,40);"
|
<div
|
||||||
|
style="position: fixed; width: 100vw; height: 100vh; z-index: 300; left: 0px; top: 0px; display: flex; flex-direction: column; background: rgb(40,40,40);"
|
||||||
*ngIf="mobileTerminalVisible">
|
*ngIf="mobileTerminalVisible">
|
||||||
<div style="display: flex; justify-content: space-between; width: 100%; height: 40px; line-height: 40px;">
|
<div style="display: flex; justify-content: space-between; width: 100%; height: 40px; line-height: 40px;">
|
||||||
<span style="padding-left: 10px; color: white;">Terminal</span>
|
<span style="padding-left: 10px; color: white;">Terminal</span>
|
||||||
<div style="display: flex;">
|
<div style="display: flex;">
|
||||||
<span class="device-keyboard" tabindex="0" (click)="k.focus()" #k><i class="fa fa-keyboard-o" aria-hidden="true"></i></span>
|
<span class="device-keyboard" tabindex="0" (click)="k.focus()" #k><i class="fa fa-keyboard-o"
|
||||||
|
aria-hidden="true"></i></span>
|
||||||
<span style="padding-right: 10px; cursor: pointer; color: white;" (click)="mobileTerminalVisible=false">
|
<span style="padding-right: 10px; cursor: pointer; color: white;" (click)="mobileTerminalVisible=false">
|
||||||
<i class="fa fa-times"></i></span>
|
<i class="fa fa-times"></i></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<app-terminal class="term-fullscreen" [socket]="session.socket" [oldText]="session.bufferText" [appId]="session.appId"
|
<app-terminal class="term-fullscreen" [socket]="session.socket" [oldText]="session.bufferText" [appId]="session.appId"
|
||||||
|
@ -0,0 +1,13 @@
|
|||||||
|
.search-box{
|
||||||
|
border-bottom: 1px solid green;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-text{
|
||||||
|
border: none;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-text:focus{
|
||||||
|
outline: none;
|
||||||
|
}
|
@ -1,3 +1,97 @@
|
|||||||
<p>
|
<div
|
||||||
monitoring works!
|
style="height: calc(100vh - 55px); width: 100vw; display: flex; flex-direction: column; position: fixed; top: 55px; left: 0px; background: white; z-index: 10;">
|
||||||
</p>
|
<div style="display: flex; justify-content: space-around; flex-wrap: wrap; padding: 20px;">
|
||||||
|
<div>
|
||||||
|
<div style="text-align: center; padding: 10px; font-size: 20px;">
|
||||||
|
<span>CPU USAGE {{cpuUsageSet[0][0].toFixed(1)}}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container" style="height:200px; position: relative; width: 200px;">
|
||||||
|
<canvas baseChart [data]="cpuUsageSet" [labels]="doughnutChartLabels" [chartType]="doughnutChartType" [colors]="colors"
|
||||||
|
[options]="options">
|
||||||
|
</canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style="text-align: center; padding: 10px; font-size: 20px;">
|
||||||
|
<span>MEMORY USAGE {{memoryUsageSet[0][0].toFixed(1)}}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container" style="height:200px; position: relative; width: 200px;">
|
||||||
|
<canvas baseChart [data]="memoryUsageSet" [labels]="doughnutChartLabels" [chartType]="doughnutChartType" [colors]="colors"
|
||||||
|
[options]="options">
|
||||||
|
</canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style="text-align: center; padding: 10px; font-size: 20px;">
|
||||||
|
<span>DISKSPACE USAGE {{diskUsageSet[0][0].toFixed(1)}}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container" style="height:200px; position: relative; width: 200px;">
|
||||||
|
<canvas baseChart [data]="diskUsageSet" [labels]="doughnutChartLabels" [chartType]="doughnutChartType" [colors]="colors"
|
||||||
|
[options]="options">
|
||||||
|
</canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div style="text-align: center; padding: 10px; font-size: 20px;">
|
||||||
|
<span>SWAP USAGE {{swapUsageSet[0][0].toFixed(1)}}%</span>
|
||||||
|
</div>
|
||||||
|
<div class="chart-container" style="height:200px; position: relative; width: 200px;">
|
||||||
|
<canvas baseChart [data]="swapUsageSet" [labels]="doughnutChartLabels" [chartType]="doughnutChartType" [colors]="colors"
|
||||||
|
[options]="options">
|
||||||
|
</canvas>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="padding:20px; padding-bottom: 10px; display: flex; justify-content: space-between;">
|
||||||
|
<div>
|
||||||
|
<span style="line-height: 30px;">Processes</span>
|
||||||
|
</div>
|
||||||
|
<div style="display: flex;">
|
||||||
|
<div style="display: flex; padding-right: 10px;" class="search-box" tabindex="0">
|
||||||
|
<input type="text" class="search-text" placeholder="Search process">
|
||||||
|
<span>
|
||||||
|
<i class="fa fa-search" aria-hidden="true"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<button class="btn btn-primary btn-sm mr-2" (click)="killSelectedProcesses()">Kill process</button>
|
||||||
|
<button class="btn btn-primary btn-sm" (click)="getProcStats()">Refresh</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div style="width: 100%; flex: 1; overflow: auto; border: 1px solid rgb(230,230,230);">
|
||||||
|
<table class="table table-striped table-sm table-borderless" style="position: relative;">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">NAME</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">PID</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">PRIORITY</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">CPU USAGE</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">MEMORY</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">VIRTUAL MEMORY</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">USER</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">START TIME</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">STATE</th>
|
||||||
|
<th scope="col" style="position: sticky; top: 0px; background: white;">COMMAND</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<tr *ngFor="let proc of processList">
|
||||||
|
<td><input type="checkbox" [checked]="proc.selected"
|
||||||
|
(change)="proc.selected = !proc.selected" ><span style="padding-left: 10px;">{{proc.name}}</span></td>
|
||||||
|
<td>{{proc.pid}}</td>
|
||||||
|
<td>{{proc.priority}}</td>
|
||||||
|
<td>{{proc.cpuUsage}}</td>
|
||||||
|
<td>{{proc.memoryUsage}}</td>
|
||||||
|
<td>{{proc.vmUsage}}</td>
|
||||||
|
<td>{{proc.user}}</td>
|
||||||
|
<td>{{proc.startTime}}</td>
|
||||||
|
<td>{{proc.state}}</td>
|
||||||
|
<td style="overflow-wrap: break-word; max-width: 200px;">
|
||||||
|
{{proc.command}}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,15 +1,119 @@
|
|||||||
import { Component, OnInit } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { ChartType, ChartOptions } from 'chart.js';
|
||||||
|
import { MultiDataSet, Label, Colors, Color } from 'ng2-charts';
|
||||||
|
import { DataService } from 'src/app/data.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-monitoring',
|
selector: 'app-monitoring',
|
||||||
templateUrl: './monitoring.component.html',
|
templateUrl: './monitoring.component.html',
|
||||||
styleUrls: ['./monitoring.component.css']
|
styleUrls: ['./monitoring.component.css'],
|
||||||
|
host: {
|
||||||
|
'(window:resize)': 'onResize($event)'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
export class MonitoringComponent implements OnInit {
|
export class MonitoringComponent implements OnInit {
|
||||||
|
|
||||||
constructor() { }
|
public doughnutChartLabels: Label[] = ['Used', 'Free'];
|
||||||
|
public colors: Color[] = [
|
||||||
|
{
|
||||||
|
backgroundColor: ['Orange', 'SteelBlue'],
|
||||||
|
borderColor: ['Orange', 'SteelBlue']
|
||||||
|
}
|
||||||
|
];
|
||||||
|
public cpuUsageSet: MultiDataSet = [
|
||||||
|
[0, 100]
|
||||||
|
];
|
||||||
|
public memoryUsageSet: MultiDataSet = [
|
||||||
|
[0, 100]
|
||||||
|
];
|
||||||
|
public diskUsageSet: MultiDataSet = [
|
||||||
|
[0, 100]
|
||||||
|
];
|
||||||
|
public swapUsageSet: MultiDataSet = [
|
||||||
|
[0, 100]
|
||||||
|
];
|
||||||
|
public doughnutChartType: ChartType = 'doughnut';
|
||||||
|
public options: ChartOptions = {
|
||||||
|
maintainAspectRatio: false,
|
||||||
|
legend: {
|
||||||
|
display: false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
timer: any;
|
||||||
|
|
||||||
|
processList: any[] = [];
|
||||||
|
|
||||||
|
constructor(private service: DataService) { }
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.getStats();
|
||||||
|
this.getProcStats();
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
this.getStats();
|
||||||
|
}, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getProcStats() {
|
||||||
|
this.service.getProcessList().subscribe((resp: any[]) => {
|
||||||
|
this.processList = resp;
|
||||||
|
for (let proc of this.processList) {
|
||||||
|
proc.selected = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public killSelectedProcesses() {
|
||||||
|
let pids: number[] = [];
|
||||||
|
for (let proc of this.processList) {
|
||||||
|
if (proc.selected) {
|
||||||
|
pids.push(proc.pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pids.length < 1) {
|
||||||
|
alert("Nothing selected to kill");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.service.killProcesses(pids).subscribe((resp: any) => {
|
||||||
|
if (!resp.success) {
|
||||||
|
alert("Failed to kill");
|
||||||
|
} else {
|
||||||
|
this.getProcStats();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelected(item: any, selection: boolean) {
|
||||||
|
item.selected = selection;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getStats() {
|
||||||
|
this.service.getSystemStats().subscribe((resp: any) => {
|
||||||
|
this.cpuUsageSet = [
|
||||||
|
[resp.cpuUsed, resp.cpuFree]
|
||||||
|
];
|
||||||
|
this.memoryUsageSet = [
|
||||||
|
[resp.memoryUsed, resp.memoryFree]
|
||||||
|
];
|
||||||
|
this.diskUsageSet = [
|
||||||
|
[resp.diskUsed, resp.diskFree]
|
||||||
|
];
|
||||||
|
this.swapUsageSet = [
|
||||||
|
[resp.swapUsed, resp.swapFree]
|
||||||
|
];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public chartClicked({ event, active }: { event: MouseEvent, active: {}[] }): void {
|
||||||
|
console.log(event, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
public chartHovered({ event, active }: { event: MouseEvent, active: {}[] }): void {
|
||||||
|
console.log(event, active);
|
||||||
|
}
|
||||||
|
|
||||||
|
onResize(event: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user