Skip to content

Commit

Permalink
feat: advance function monitor
Browse files Browse the repository at this point in the history
  • Loading branch information
zyyzyykk committed Feb 6, 2025
1 parent fed7ded commit 1e1da87
Show file tree
Hide file tree
Showing 16 changed files with 782 additions and 38 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,15 @@
import com.kkbpro.terminal.utils.AesUtil;
import com.kkbpro.terminal.utils.StringUtil;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.BufferedReader;
import java.io.InputStreamReader;

/**
* 高级功能接口类
*/
Expand All @@ -21,10 +26,10 @@ public class AdvanceController {
public static final String COOPERATE_SECRET_KEY = "o4D1fYuVp2js9xKX";

/**
* 获取协作id
* 获取协作Key
*/
@GetMapping("/cooperate")
public Result getCooperateId(String sshKey, Boolean readOnly, Integer maxHeadCount) throws Exception {
public Result cooperate(String sshKey, Boolean readOnly, Integer maxHeadCount) throws Exception {
String errorMsg = "协作Key生成失败";
String successMsg = "协作Key生成成功";

Expand All @@ -46,7 +51,71 @@ public Result getCooperateId(String sshKey, Boolean readOnly, Integer maxHeadCou
return Result.success(successMsg, key);
}

// 完整命令
// echo -n "$(uptime | awk -F'load average: ' '{print $2}' | awk '{print $1}' | sed 's/,//')@" && \
// echo -n "$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')@" && \
// echo -n "$(nproc)@" && \
// echo -n "$(free -m | grep Mem | awk '{print $3"@"$2}')@" && \
// echo -n "$(df -BMB / | grep / | awk '{print $3"@"$2}' | sed 's/[A-Za-z]//g')" && \
// echo -n "^" && \
// echo -n "$(ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | head -n 5 | awk 'NR>1 {print $1"@"$2"@"$3"@"$4"@"$5}' | tr '\n' '$' | sed 's/\(.*\)\$$/\1/')" && \
// echo -n "^" && \
// echo -n "$(cat /proc/net/dev | awk 'NR>2 {up+=$10; down+=$2;} END {print "all:@"up"@"down}')" && \
// echo -n "$" && \
// echo -n "$(cat /proc/net/dev | awk 'NR>2 {print $1"@"$10"@"$2}' | tr -s ' ' '@' | tr '\n' '$' | sed 's/\(.*\)\$/\1/')" && \
// echo -n "^" && \
// echo -n "$(cat /proc/diskstats | awk '{if($3 ~ /[^0-9]$/) {read+=$6; write+=$10}} END {print "all@" read"@"write}')" && \
// echo -n "$" && \
// echo -n "$(cat /proc/diskstats | awk '{print $3"@"$6"@"$10}' | tr -s ' ' '@' | tr '\n' '$' | sed 's/\(.*\)\$/\1/')" && \
// echo -n "^" && \
// echo -n $(date +%s%3N)
/**
* 获取监控状态
*/
@PostMapping("/monitor")
public Result monitor(String sshKey) {
String errorMsg = "获取监控状态失败";
String successMsg = "获取监控状态成功";

SSHClient ssh = WebSocketServer.sshClientMap.get(sshKey);
if(ssh == null) {
return Result.error(FileBlockStateEnum.SSH_NOT_EXIST.getState(),"连接断开," + errorMsg);
}
String status = "";
String command = "echo -n \"$(uptime | awk -F'load average: ' '{print $2}' | awk '{print $1}' | sed 's/,//')@\" && \\\n" +
"echo -n \"$(top -bn1 | grep \"Cpu(s)\" | sed \"s/.*, *\\([0-9.]*\\)%* id.*/\\1/\" | awk '{print 100 - $1}')@\" && \\\n" +
"echo -n \"$(nproc)@\" && \\\n" +
"echo -n \"$(free -m | grep Mem | awk '{print $3\"@\"$2}')@\" && \\\n" +
"echo -n \"$(df -BMB / | grep / | awk '{print $3\"@\"$2}' | sed 's/[A-Za-z]//g')\" && \\\n" +
"echo -n \"^\" && \\\n" +
"echo -n \"$(ps -eo pid,user,%cpu,%mem,comm --sort=-%cpu | head -n 5 | awk 'NR>1 {print $1\"@\"$2\"@\"$3\"@\"$4\"@\"$5}' | tr '\\n' '$' | sed 's/\\(.*\\)\\$$/\\1/')\" && \\\n" +
"echo -n \"^\" && \\\n" +
"echo -n \"$(cat /proc/net/dev | awk 'NR>2 {up+=$10; down+=$2;} END {print \"all:@\"up\"@\"down}')\" && \\\n" +
"echo -n \"$\" && \\\n" +
"echo -n \"$(cat /proc/net/dev | awk 'NR>2 {print $1\"@\"$10\"@\"$2}' | tr -s ' ' '@' | tr '\\n' '$' | sed 's/\\(.*\\)\\$/\\1/')\" && \\\n" +
"echo -n \"^\" && \\\n" +
"echo -n \"$(cat /proc/diskstats | awk '{if($3 ~ /[^0-9]$/) {read+=$6; write+=$10}} END {print \"all@\" read\"@\"write}')\" && \\\n" +
"echo -n \"$\" && \\\n" +
"echo -n \"$(cat /proc/diskstats | awk '{print $3\"@\"$6\"@\"$10}' | tr -s ' ' '@' | tr '\\n' '$' | sed 's/\\(.*\\)\\$/\\1/')\" && \\\n" +
"echo -n \"^\" && \\\n" +
"echo -n $(date +%s%3N)";
try(Session session = ssh.startSession();
Session.Command cmd = session.exec(command))
{
// 读取命令执行结果
try (BufferedReader reader = new BufferedReader(new InputStreamReader(cmd.getInputStream()))) {
status += reader.readLine();
}
// 等待命令执行完毕
cmd.join();
int exitStatus = cmd.getExitStatus();
if (exitStatus != 0) return Result.error(errorMsg);
} catch (Exception e) {
e.printStackTrace();
return Result.error(errorMsg);
}
return Result.success(200, successMsg, status);
}


}
4 changes: 3 additions & 1 deletion backend/terminal/src/main/resources/locales/en_US.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,7 @@
"云端文件过多": "Too many Cloud Files",
"云端上传成功": "Cloud File Uploaded",
"协作Key生成成功": "Cooperate Key Generate Success",
"协作Key生成失败": "Cooperate Key Generate Failed"
"协作Key生成失败": "Cooperate Key Generate Failed",
"获取监控状态成功": "Obtain Monitor Status Success",
"获取监控状态失败": "Obtain Monitor Status Failed"
}
28 changes: 28 additions & 0 deletions front/terminal/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions front/terminal/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"ace-builds": "^1.32.5",
"core-js": "^3.8.3",
"crypto-js": "^4.1.1",
"echarts": "^5.6.0",
"element-plus": "^2.9.3",
"file-icons-vue": "^1.3.4",
"iconv-lite": "^0.6.3",
Expand Down
10 changes: 9 additions & 1 deletion front/terminal/src/components/StyleSetting.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<el-dialog
v-model="DialogVisible"
destroy-on-close
:width="426"
:width="$t('450')"
:title="$t('偏好设置')"
:modal="false"
modal-class="kk-dialog-class"
Expand Down Expand Up @@ -94,6 +94,12 @@
<el-switch v-model="setInfo.cloud" />
</div>
</div>
<div class="item-class">
<div>{{ $t('高级') }}</div>
<div style="margin: 0 20px;" >
<el-switch v-model="setInfo.advance" />
</div>
</div>
</div>
<div class="item-class" style="margin-bottom: 5px;">
<div class="form-width" >{{ $t('其它') }}:</div>
Expand Down Expand Up @@ -170,6 +176,7 @@ export default {
cursorBlink: props.env.cursorBlink,
tCode: props.env.tCode,
cloud: props.env.cloud,
advance: props.env.advance,
});
const confirm = () => {
context.emit('callback',setInfo.value);
Expand All @@ -188,6 +195,7 @@ export default {
cursorBlink: props.env.cursorBlink,
tCode: props.env.tCode,
cloud: props.env.cloud,
advance: props.env.advance,
};
DialogVisible.value = false;
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<el-dialog
v-model="DialogVisible"
v-model="computedDialogVisible"
:before-close="closeDialog"
:width="$t('240')"
:modal="false"
Expand Down Expand Up @@ -42,21 +42,25 @@
</template>

<script>
import { ref } from 'vue';
import { ref,computed } from 'vue';
import useClipboard from "vue-clipboard3";
import $ from 'jquery';
import { ElMessage } from 'element-plus';
import { http_base_url } from '@/env/BaseUrl';
import i18n from "@/locales/i18n";
import {getPureUrl} from "@/utils/UrlUtil";
import { getPureUrl } from "@/utils/UrlUtil";
export default {
name: 'CooperateGen',
props:['sshKey'],
props:['sshKey', 'advance'],
setup(props, context) {
// 控制Dialog显示
const DialogVisible = ref(false);
const computedDialogVisible = computed(() => {
return DialogVisible.value && props.advance;
});
const isReadonly = ref(true);
const maxHeadCount = ref(6);
Expand Down Expand Up @@ -117,6 +121,7 @@ export default {
};
return {
computedDialogVisible,
DialogVisible,
confirm,
closeDialog,
Expand Down
81 changes: 81 additions & 0 deletions front/terminal/src/components/advance/EChart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<template>
<div element-loading-text="Loading..." v-loading="loading" ref="echartRef" ></div>
</template>

<script>
import { onMounted, ref } from 'vue';
import * as echarts from 'echarts';
export default {
name: 'EChart',
props: ['legend', 'yName'],
setup(props) {
const loading = ref(true);
const echartRef = ref();
const option = {
title: {
text: '',
},
tooltip: {
trigger: 'axis'
},
legend: {
data: props.legend,
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: [],
},
yAxis: {
name : props.yName,
type: 'value'
},
series: [],
};
let chart = null;
const update = (time,series) => {
option.xAxis.data = time;
option.series = series;
// 更新图表
if (chart) {
loading.value = true;
chart.setOption(option);
}
};
onMounted(() => {
// 初始化ECharts实例并应用配置项
chart = echarts.init(echartRef.value);
chart.on('rendered', function() {
loading.value = false;
});
loading.value = true;
chart.setOption(option);
chart.resize();
});
return {
echartRef,
update,
}
}
}
</script>

<style scoped >
/* 文本不可选中 */
.no-select {
user-select: none;
}
</style>
Loading

0 comments on commit 1e1da87

Please sign in to comment.