mirror of
https://github.com/wikihost-opensource/als.git
synced 2025-12-24 12:57:59 +08:00
Merge pull request #13 from wikihost-opensource/master-cf-autofix
Apply fixes from CodeFactor
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
|
||||
|
||||
<template>
|
||||
<n-config-provider :theme="darkTheme">
|
||||
<n-message-provider>
|
||||
@@ -7,14 +5,32 @@
|
||||
<div v-show="isLoaded">
|
||||
<n-space vertical>
|
||||
<h2>Looking Glass Server</h2>
|
||||
<Information v-model:wsMessage="wsMessage" v-model:componentConfig="componentConfig"></Information>
|
||||
<Utilities v-model:componentConfig="componentConfig" v-model:ws="ws" v-model:wsMessage="wsMessage">
|
||||
<Information
|
||||
v-model:wsMessage="wsMessage"
|
||||
v-model:componentConfig="componentConfig"
|
||||
></Information>
|
||||
<Utilities
|
||||
v-model:componentConfig="componentConfig"
|
||||
v-model:ws="ws"
|
||||
v-model:wsMessage="wsMessage"
|
||||
>
|
||||
</Utilities>
|
||||
<Speedtest v-model:componentConfig="componentConfig" v-show="componentConfig.display_speedtest"></Speedtest>
|
||||
<TrafficDisplay v-show="componentConfig.display_traffic" v-model:wsMessage="wsMessage"></TrafficDisplay>
|
||||
<Speedtest
|
||||
v-model:componentConfig="componentConfig"
|
||||
v-show="componentConfig.display_speedtest"
|
||||
></Speedtest>
|
||||
<TrafficDisplay
|
||||
v-show="componentConfig.display_traffic"
|
||||
v-model:wsMessage="wsMessage"
|
||||
></TrafficDisplay>
|
||||
<div>
|
||||
Powered by
|
||||
<n-button text tag="a" target="_blank" href="https://github.com/wikihost-opensource/als">
|
||||
<n-button
|
||||
text
|
||||
tag="a"
|
||||
target="_blank"
|
||||
href="https://github.com/wikihost-opensource/als"
|
||||
>
|
||||
WIKIHOST Opensource - ALS (Github)
|
||||
</n-button>
|
||||
</div>
|
||||
@@ -24,16 +40,20 @@
|
||||
</n-config-provider>
|
||||
</template>
|
||||
<script>
|
||||
import Loading from './components/Loading.vue'
|
||||
import { defineComponent, defineAsyncComponent, reactive } from 'vue'
|
||||
import { darkTheme } from 'naive-ui'
|
||||
import Loading from "./components/Loading.vue";
|
||||
import { defineComponent, defineAsyncComponent, reactive } from "vue";
|
||||
import { darkTheme } from "naive-ui";
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
Information: defineAsyncComponent(() => import('./components/Information.vue')),
|
||||
TrafficDisplay: defineAsyncComponent(() => import('./components/TrafficDisplay.vue')),
|
||||
Speedtest: defineAsyncComponent(() => import('./components/Speedtest.vue')),
|
||||
Utilities: defineAsyncComponent(() => import('./components/Utilities.vue')),
|
||||
Information: defineAsyncComponent(() =>
|
||||
import("./components/Information.vue")
|
||||
),
|
||||
TrafficDisplay: defineAsyncComponent(() =>
|
||||
import("./components/TrafficDisplay.vue")
|
||||
),
|
||||
Speedtest: defineAsyncComponent(() => import("./components/Speedtest.vue")),
|
||||
Utilities: defineAsyncComponent(() => import("./components/Utilities.vue")),
|
||||
},
|
||||
created() {
|
||||
this.initWebsocket();
|
||||
@@ -41,27 +61,29 @@ export default defineComponent({
|
||||
methods: {
|
||||
initWebsocket() {
|
||||
if (this.isLoaded || this.isConnecting) return;
|
||||
this.isConnecting = true
|
||||
this.ws = new WebSocket(location.protocol.replace('http', 'ws') + '//' + location.host + '/ws')
|
||||
this.isConnecting = true;
|
||||
this.ws = new WebSocket(
|
||||
location.protocol.replace("http", "ws") + "//" + location.host + "/ws"
|
||||
);
|
||||
this.ws.onopen = () => {
|
||||
this.isLoaded = true
|
||||
this.isConnecting = false
|
||||
}
|
||||
this.isLoaded = true;
|
||||
this.isConnecting = false;
|
||||
};
|
||||
this.ws.onmessage = (message) => {
|
||||
this.wsMessage.push(message.data.split('|'))
|
||||
this.wsMessage.push(message.data.split("|"));
|
||||
};
|
||||
|
||||
let error_or_closed = () => {
|
||||
this.isLoaded = false
|
||||
this.isConnecting = false
|
||||
this.ws.close()
|
||||
this.ws = null
|
||||
this.initWebsocket()
|
||||
}
|
||||
this.isLoaded = false;
|
||||
this.isConnecting = false;
|
||||
this.ws.close();
|
||||
this.ws = null;
|
||||
this.initWebsocket();
|
||||
};
|
||||
|
||||
this.ws.onclose = error_or_closed
|
||||
this.ws.onerror = error_or_closed
|
||||
}
|
||||
this.ws.onclose = error_or_closed;
|
||||
this.ws.onerror = error_or_closed;
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@@ -69,18 +91,18 @@ export default defineComponent({
|
||||
wsMessage: reactive([]),
|
||||
isLoaded: false,
|
||||
isConnecting: false,
|
||||
componentConfig: reactive({})
|
||||
}
|
||||
componentConfig: reactive({}),
|
||||
};
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
darkTheme
|
||||
}
|
||||
}
|
||||
})
|
||||
darkTheme,
|
||||
};
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style>
|
||||
@import './assets/base.css';
|
||||
@import "./assets/base.css";
|
||||
|
||||
#app {
|
||||
max-width: 1280px;
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
<template>
|
||||
<div>
|
||||
|
||||
<n-card hoverable>
|
||||
<template #header>
|
||||
服务器信息
|
||||
</template>
|
||||
<n-table style="max-width: 500px;border: none;">
|
||||
<tbody>
|
||||
<template v-for="data in tableData">
|
||||
<tr>
|
||||
<td>{{ data.key }}</td>
|
||||
<td>
|
||||
<n-button text @click="copySomething(data.value)">{{ data.value }}</n-button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</n-table>
|
||||
<!-- <n-space vertical>
|
||||
<div>
|
||||
<n-card hoverable>
|
||||
<template #header> 服务器信息 </template>
|
||||
<n-table style="max-width: 500px; border: none">
|
||||
<tbody>
|
||||
<template v-for="data in tableData">
|
||||
<tr>
|
||||
<td>{{ data.key }}</td>
|
||||
<td>
|
||||
<n-button text @click="copySomething(data.value)">{{
|
||||
data.value
|
||||
}}</n-button>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</n-table>
|
||||
<!-- <n-space vertical>
|
||||
<div v-show="location">
|
||||
服务器地点: {{ location }}
|
||||
</div>
|
||||
@@ -31,80 +30,83 @@
|
||||
您当前的 IP 地址: {{ clientIp }}
|
||||
</div>
|
||||
</n-space> -->
|
||||
<!-- <n-progress type=" line" :percentage="100" :show-indicator="false" processing /> -->
|
||||
</n-card>
|
||||
</div>
|
||||
|
||||
<!-- <n-progress type=" line" :percentage="100" :show-indicator="false" processing /> -->
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent } from 'vue'
|
||||
import useClipboard from 'vue-clipboard3'
|
||||
import { useMessage } from 'naive-ui'
|
||||
import { defineComponent } from "vue";
|
||||
import useClipboard from "vue-clipboard3";
|
||||
import { useMessage } from "naive-ui";
|
||||
|
||||
const { toClipboard } = useClipboard()
|
||||
const { toClipboard } = useClipboard();
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
componentConfig: Object
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
componentConfig: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
copySomething(String) {
|
||||
toClipboard(String, "copy");
|
||||
window.$message.success("已复制");
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tableData: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
copySomething(String) {
|
||||
toClipboard(String, 'copy')
|
||||
window.$message.success('已复制')
|
||||
}
|
||||
},
|
||||
setup() {
|
||||
window.$message = useMessage()
|
||||
},
|
||||
mounted() {
|
||||
let DataWatcher = this.$watch(() => this.wsMessage, () => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 1000) return;
|
||||
let data = JSON.parse(e[1])
|
||||
this.wsMessage.splice(i, 1)
|
||||
this.componentConfig.public_ipv4 = data.public_ipv4
|
||||
this.componentConfig.public_ipv6 = data.public_ipv6
|
||||
this.componentConfig.testFiles = data.testfiles
|
||||
this.componentConfig.display_traffic = data.display_traffic
|
||||
this.componentConfig.display_speedtest = data.display_speedtest
|
||||
this.componentConfig.utilities_ping = data.utilities_ping
|
||||
this.componentConfig.utilities_traceroute = data.utilities_traceroute
|
||||
this.componentConfig.utilities_iperf3 = data.utilities_iperf3
|
||||
},
|
||||
setup() {
|
||||
window.$message = useMessage();
|
||||
},
|
||||
mounted() {
|
||||
let DataWatcher = this.$watch(
|
||||
() => this.wsMessage,
|
||||
() => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 1000) return;
|
||||
let data = JSON.parse(e[1]);
|
||||
this.wsMessage.splice(i, 1);
|
||||
this.componentConfig.public_ipv4 = data.public_ipv4;
|
||||
this.componentConfig.public_ipv6 = data.public_ipv6;
|
||||
this.componentConfig.testFiles = data.testfiles;
|
||||
this.componentConfig.display_traffic = data.display_traffic;
|
||||
this.componentConfig.display_speedtest = data.display_speedtest;
|
||||
this.componentConfig.utilities_ping = data.utilities_ping;
|
||||
this.componentConfig.utilities_traceroute = data.utilities_traceroute;
|
||||
this.componentConfig.utilities_iperf3 = data.utilities_iperf3;
|
||||
|
||||
this.tableData = []
|
||||
this.tableData.push({
|
||||
key: '服务器位置',
|
||||
value: data.location
|
||||
})
|
||||
this.tableData = [];
|
||||
this.tableData.push({
|
||||
key: "服务器位置",
|
||||
value: data.location,
|
||||
});
|
||||
|
||||
if (data.public_ipv4) {
|
||||
this.tableData.push({
|
||||
key: 'IPv4 地址',
|
||||
value: data.public_ipv4
|
||||
})
|
||||
}
|
||||
if (data.public_ipv4) {
|
||||
this.tableData.push({
|
||||
key: "IPv4 地址",
|
||||
value: data.public_ipv4,
|
||||
});
|
||||
}
|
||||
|
||||
if (data.public_ipv4) {
|
||||
this.tableData.push({
|
||||
key: 'IPv6 地址',
|
||||
value: data.public_ipv6
|
||||
})
|
||||
}
|
||||
if (data.public_ipv4) {
|
||||
this.tableData.push({
|
||||
key: "IPv6 地址",
|
||||
value: data.public_ipv6,
|
||||
});
|
||||
}
|
||||
|
||||
this.tableData.push({
|
||||
key: '您当前的 IP 地址',
|
||||
value: data.client_ip
|
||||
})
|
||||
DataWatcher()
|
||||
})
|
||||
}, { immediate: true, deep: true });
|
||||
}
|
||||
})
|
||||
</script>
|
||||
this.tableData.push({
|
||||
key: "您当前的 IP 地址",
|
||||
value: data.client_ip,
|
||||
});
|
||||
DataWatcher();
|
||||
});
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
<template>
|
||||
<div class="loading-screen">
|
||||
<n-card title="Loading...">
|
||||
<n-progress type="line" :percentage="100" :show-indicator="false" processing />
|
||||
</n-card>
|
||||
</div>
|
||||
<div class="loading-screen">
|
||||
<n-card title="Loading...">
|
||||
<n-progress
|
||||
type="line"
|
||||
:percentage="100"
|
||||
:show-indicator="false"
|
||||
processing
|
||||
/>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export {
|
||||
|
||||
}
|
||||
</script>
|
||||
export {};
|
||||
</script>
|
||||
|
||||
@@ -1,282 +1,317 @@
|
||||
<template>
|
||||
<n-card>
|
||||
<template #header>
|
||||
服务器网络测速
|
||||
</template>
|
||||
<div v-show="h5Download !== '...'">
|
||||
<n-grid x-gap="12" cols="1 s:1 m:1 l:3" responsive="screen">
|
||||
<n-gi span="1 s:1 m:1 l:2">
|
||||
<div>
|
||||
<h4>下行</h4>
|
||||
<h1>{{ h5Download }} Mbps</h1>
|
||||
<apexchart type="line" :options="h5SpeedtestDownloadSpeedChart.chartOptions" height="200px"
|
||||
:series="h5SpeedtestDownloadSpeedChart.series">
|
||||
</apexchart>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi span="1">
|
||||
<div>
|
||||
<h4>上行</h4>
|
||||
<h1>{{ h5Upload }} Mbps</h1>
|
||||
<apexchart type="line" :options="h5SpeedtestUploadSpeedChart.chartOptions" height="200px"
|
||||
:series="h5SpeedtestUploadSpeedChart.series">
|
||||
</apexchart>
|
||||
</div>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</div>
|
||||
<!-- <h3>下行:
|
||||
<n-card>
|
||||
<template #header> 服务器网络测速 </template>
|
||||
<div v-show="h5Download !== '...'">
|
||||
<n-grid x-gap="12" cols="1 s:1 m:1 l:3" responsive="screen">
|
||||
<n-gi span="1 s:1 m:1 l:2">
|
||||
<div>
|
||||
<h4>下行</h4>
|
||||
<h1>{{ h5Download }} Mbps</h1>
|
||||
<apexchart
|
||||
type="line"
|
||||
:options="h5SpeedtestDownloadSpeedChart.chartOptions"
|
||||
height="200px"
|
||||
:series="h5SpeedtestDownloadSpeedChart.series"
|
||||
>
|
||||
</apexchart>
|
||||
</div>
|
||||
</n-gi>
|
||||
<n-gi span="1">
|
||||
<div>
|
||||
<h4>上行</h4>
|
||||
<h1>{{ h5Upload }} Mbps</h1>
|
||||
<apexchart
|
||||
type="line"
|
||||
:options="h5SpeedtestUploadSpeedChart.chartOptions"
|
||||
height="200px"
|
||||
:series="h5SpeedtestUploadSpeedChart.series"
|
||||
>
|
||||
</apexchart>
|
||||
</div>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</div>
|
||||
<!-- <h3>下行:
|
||||
<n-number-animation :to="h5Download" />
|
||||
</h3>
|
||||
<h3>上行: {{ h5Upload }}</h3> -->
|
||||
<n-space justify="space-evenly">
|
||||
<n-button size="large" @click="startOrStopSpeedtest" style="margin-top: 10px;">
|
||||
<n-spin size="small" v-show="h5SpeedWorker !== null" style="margin-right: 10px;" /> {{
|
||||
h5SpeedtestButtonText
|
||||
}}
|
||||
<n-space justify="space-evenly">
|
||||
<n-button
|
||||
size="large"
|
||||
@click="startOrStopSpeedtest"
|
||||
style="margin-top: 10px"
|
||||
>
|
||||
<n-spin
|
||||
size="small"
|
||||
v-show="h5SpeedWorker !== null"
|
||||
style="margin-right: 10px"
|
||||
/>
|
||||
{{ h5SpeedtestButtonText }}
|
||||
</n-button>
|
||||
</n-space>
|
||||
<n-divider v-show="componentConfig?.testFiles?.length > 0" dashed />
|
||||
<n-space
|
||||
v-if="componentConfig?.testFiles?.length > 0"
|
||||
justify="space-evenly"
|
||||
>
|
||||
<div v-if="componentConfig.public_ipv4">
|
||||
<h3 style="text-align: center">IPv4 下载测试</h3>
|
||||
<n-space>
|
||||
<template v-for="i in componentConfig.testFiles">
|
||||
<n-button
|
||||
strong
|
||||
secondary
|
||||
type="info"
|
||||
size="small"
|
||||
tag="a"
|
||||
:href="`//${componentConfig.public_ipv4}/speedtest-static/${i}.test`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ i }}
|
||||
</n-button>
|
||||
</template>
|
||||
</n-space>
|
||||
<n-divider v-show="componentConfig?.testFiles?.length > 0" dashed />
|
||||
<n-space v-if="componentConfig?.testFiles?.length > 0" justify="space-evenly">
|
||||
</div>
|
||||
|
||||
<div v-if="componentConfig.public_ipv4">
|
||||
<h3 style="text-align: center;">IPv4 下载测试</h3>
|
||||
<n-space>
|
||||
<template v-for="i in componentConfig.testFiles">
|
||||
<n-button strong secondary type="info" size="small" tag="a"
|
||||
:href="`//${componentConfig.public_ipv4}/speedtest-static/${i}.test`" target="_blank">
|
||||
{{ i }}
|
||||
</n-button>
|
||||
</template>
|
||||
</n-space>
|
||||
</div>
|
||||
|
||||
<div v-if="componentConfig.public_ipv6">
|
||||
<h3 style="text-align: center;">IPv6 下载测试</h3>
|
||||
<n-space>
|
||||
<template v-for="i in componentConfig.testFiles">
|
||||
<n-button strong secondary type="info" size="small" tag="a"
|
||||
:href="`//[${componentConfig.public_ipv6}]/speedtest-static/${i}.test`" target="_blank">
|
||||
{{ i }}
|
||||
</n-button>
|
||||
</template>
|
||||
</n-space>
|
||||
</div>
|
||||
<div v-if="componentConfig.public_ipv6">
|
||||
<h3 style="text-align: center">IPv6 下载测试</h3>
|
||||
<n-space>
|
||||
<template v-for="i in componentConfig.testFiles">
|
||||
<n-button
|
||||
strong
|
||||
secondary
|
||||
type="info"
|
||||
size="small"
|
||||
tag="a"
|
||||
:href="`//[${componentConfig.public_ipv6}]/speedtest-static/${i}.test`"
|
||||
target="_blank"
|
||||
>
|
||||
{{ i }}
|
||||
</n-button>
|
||||
</template>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-space>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const langMap = {
|
||||
beginSpeedtest: '开始测速',
|
||||
}
|
||||
beginSpeedtest: "开始测速",
|
||||
};
|
||||
|
||||
import { defineComponent, defineAsyncComponent } from 'vue'
|
||||
import { defineComponent, defineAsyncComponent } from "vue";
|
||||
export default defineComponent({
|
||||
components: {
|
||||
apexchart: defineAsyncComponent(() => import('vue3-apexcharts')),
|
||||
},
|
||||
props: {
|
||||
componentConfig: Object
|
||||
},
|
||||
methods: {
|
||||
startOrStopSpeedtest(force = true) {
|
||||
if (this.h5SpeedWorker !== null) {
|
||||
this.h5SpeedWorker.postMessage('abort')
|
||||
clearInterval(this.h5SpeedWorkerTimer)
|
||||
this.h5SpeedtestButtonText = '开始测速'
|
||||
this.h5SpeedWorker = null
|
||||
if (force) {
|
||||
this.h5Upload = '...'
|
||||
this.h5Download = '...'
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.h5Upload = '...'
|
||||
this.h5Download = '...'
|
||||
this.h5SpeedtestButtonText = '停止测速'
|
||||
this.h5SpeedWorker = new Worker('speedtest_worker.js')
|
||||
// this
|
||||
this.h5SpeedWorker.onmessage = (e) => {
|
||||
var nowPointName = (new Date()).getHours().toString().padStart(2, '0') + ':' +
|
||||
(new Date()).getMinutes().toString().padStart(2, '0') + ':' +
|
||||
(new Date()).getSeconds().toString().padStart(2, '0')
|
||||
|
||||
var data = JSON.parse(e.data);
|
||||
var status = data.testState;
|
||||
if (status >= 4) {
|
||||
return this.startOrStopSpeedtest(false)
|
||||
}
|
||||
|
||||
if (status == 1 && data.dlStatus == 0) {
|
||||
this.h5Download = '...'
|
||||
} else {
|
||||
if (data.dlStatus) {
|
||||
if (data.dlStatus != this.h5Download) {
|
||||
this.h5Download = data.dlStatus
|
||||
let ChartData = this.h5SpeedtestDownloadSpeedChart.series[0].data
|
||||
let categories = this.h5SpeedtestDownloadSpeedChart.chartOptions.xaxis.categories
|
||||
ChartData.push(this.h5Download)
|
||||
categories.push(nowPointName)
|
||||
this.h5SpeedtestDownloadSpeedChart.chartOptions.value = {
|
||||
xaxis: { categories: categories }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status == 1 && data.ulStatus == 0) {
|
||||
this.h5Upload = '...'
|
||||
} else {
|
||||
if (data.ulStatus) {
|
||||
if (data.ulStatus != this.h5Upload) {
|
||||
this.h5Upload = data.ulStatus
|
||||
let ChartData = this.h5SpeedtestUploadSpeedChart.series[0].data
|
||||
let categories = this.h5SpeedtestUploadSpeedChart.chartOptions.xaxis.categories
|
||||
ChartData.push(this.h5Upload)
|
||||
categories.push(nowPointName)
|
||||
this.h5SpeedtestUploadSpeedChart.chartOptions.value = {
|
||||
xaxis: { categories: categories }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
this.h5SpeedWorker.postMessage('start ' + JSON.stringify({
|
||||
test_order: "D_U",
|
||||
url_dl: 'speedtest/download',
|
||||
url_ul: 'speedtest/upload',
|
||||
url_ping: 'speedtest/upload',
|
||||
}));
|
||||
this.h5SpeedWorkerTimer = setInterval(() => {
|
||||
this.h5SpeedWorker.postMessage('status')
|
||||
}, 200);
|
||||
// this.h5SpeedtestWorking = !this.h5SpeedtestWorking
|
||||
components: {
|
||||
apexchart: defineAsyncComponent(() => import("vue3-apexcharts")),
|
||||
},
|
||||
props: {
|
||||
componentConfig: Object,
|
||||
},
|
||||
methods: {
|
||||
startOrStopSpeedtest(force = true) {
|
||||
if (this.h5SpeedWorker !== null) {
|
||||
this.h5SpeedWorker.postMessage("abort");
|
||||
clearInterval(this.h5SpeedWorkerTimer);
|
||||
this.h5SpeedtestButtonText = "开始测速";
|
||||
this.h5SpeedWorker = null;
|
||||
if (force) {
|
||||
this.h5Upload = "...";
|
||||
this.h5Download = "...";
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
h5SpeedWorker: null,
|
||||
h5SpeedWorkerTimer: null,
|
||||
h5SpeedtestWorking: false,
|
||||
h5SpeedtestButtonText: langMap.beginSpeedtest,
|
||||
h5Upload: '...',
|
||||
h5Download: '...',
|
||||
h5SpeedtestDownloadSpeedChart: {
|
||||
chartOptions: {
|
||||
chart: {
|
||||
id: "speedtest-download-chart",
|
||||
height: 200,
|
||||
foreColor: '#e8e8e8',
|
||||
animations: {
|
||||
enabled: true,
|
||||
easing: 'linear',
|
||||
dynamicAnimation: {
|
||||
speed: 300
|
||||
},
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
theme: 'dark'
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: 'category',
|
||||
categories: [''],
|
||||
labels: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
formatter: (value) => {
|
||||
return value + ' Mbps'
|
||||
}
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
markers: {
|
||||
size: 0
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth'
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'line',
|
||||
name: 'Receive',
|
||||
data: []
|
||||
}
|
||||
]
|
||||
},
|
||||
h5SpeedtestUploadSpeedChart: {
|
||||
chartOptions: {
|
||||
chart: {
|
||||
id: "speedtest-upload-chart",
|
||||
height: 200,
|
||||
foreColor: '#e8e8e8',
|
||||
animations: {
|
||||
enabled: true,
|
||||
easing: 'linear',
|
||||
dynamicAnimation: {
|
||||
speed: 300
|
||||
},
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
theme: 'dark'
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: 'category',
|
||||
categories: [''],
|
||||
labels: {
|
||||
show: false
|
||||
}
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
formatter: (value) => {
|
||||
return value + ' Mbps'
|
||||
}
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
markers: {
|
||||
size: 0
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth'
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'line',
|
||||
name: 'Receive',
|
||||
data: []
|
||||
}
|
||||
]
|
||||
},
|
||||
return;
|
||||
}
|
||||
this.h5Upload = "...";
|
||||
this.h5Download = "...";
|
||||
this.h5SpeedtestButtonText = "停止测速";
|
||||
this.h5SpeedWorker = new Worker("speedtest_worker.js");
|
||||
// this
|
||||
this.h5SpeedWorker.onmessage = (e) => {
|
||||
var nowPointName =
|
||||
new Date().getHours().toString().padStart(2, "0") +
|
||||
":" +
|
||||
new Date().getMinutes().toString().padStart(2, "0") +
|
||||
":" +
|
||||
new Date().getSeconds().toString().padStart(2, "0");
|
||||
|
||||
var data = JSON.parse(e.data);
|
||||
var status = data.testState;
|
||||
if (status >= 4) {
|
||||
return this.startOrStopSpeedtest(false);
|
||||
}
|
||||
|
||||
if (status == 1 && data.dlStatus == 0) {
|
||||
this.h5Download = "...";
|
||||
} else {
|
||||
if (data.dlStatus) {
|
||||
if (data.dlStatus != this.h5Download) {
|
||||
this.h5Download = data.dlStatus;
|
||||
let ChartData = this.h5SpeedtestDownloadSpeedChart.series[0].data;
|
||||
let categories =
|
||||
this.h5SpeedtestDownloadSpeedChart.chartOptions.xaxis
|
||||
.categories;
|
||||
ChartData.push(this.h5Download);
|
||||
categories.push(nowPointName);
|
||||
this.h5SpeedtestDownloadSpeedChart.chartOptions.value = {
|
||||
xaxis: { categories: categories },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (status == 1 && data.ulStatus == 0) {
|
||||
this.h5Upload = "...";
|
||||
} else {
|
||||
if (data.ulStatus) {
|
||||
if (data.ulStatus != this.h5Upload) {
|
||||
this.h5Upload = data.ulStatus;
|
||||
let ChartData = this.h5SpeedtestUploadSpeedChart.series[0].data;
|
||||
let categories =
|
||||
this.h5SpeedtestUploadSpeedChart.chartOptions.xaxis.categories;
|
||||
ChartData.push(this.h5Upload);
|
||||
categories.push(nowPointName);
|
||||
this.h5SpeedtestUploadSpeedChart.chartOptions.value = {
|
||||
xaxis: { categories: categories },
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
this.h5SpeedWorker.postMessage(
|
||||
"start " +
|
||||
JSON.stringify({
|
||||
test_order: "D_U",
|
||||
url_dl: "speedtest/download",
|
||||
url_ul: "speedtest/upload",
|
||||
url_ping: "speedtest/upload",
|
||||
})
|
||||
);
|
||||
this.h5SpeedWorkerTimer = setInterval(() => {
|
||||
this.h5SpeedWorker.postMessage("status");
|
||||
}, 200);
|
||||
// this.h5SpeedtestWorking = !this.h5SpeedtestWorking
|
||||
},
|
||||
mounted() {
|
||||
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
h5SpeedWorker: null,
|
||||
h5SpeedWorkerTimer: null,
|
||||
h5SpeedtestWorking: false,
|
||||
h5SpeedtestButtonText: langMap.beginSpeedtest,
|
||||
h5Upload: "...",
|
||||
h5Download: "...",
|
||||
h5SpeedtestDownloadSpeedChart: {
|
||||
chartOptions: {
|
||||
chart: {
|
||||
id: "speedtest-download-chart",
|
||||
height: 200,
|
||||
foreColor: "#e8e8e8",
|
||||
animations: {
|
||||
enabled: true,
|
||||
easing: "linear",
|
||||
dynamicAnimation: {
|
||||
speed: 300,
|
||||
},
|
||||
},
|
||||
zoom: {
|
||||
enabled: false,
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
theme: "dark",
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: "category",
|
||||
categories: [""],
|
||||
labels: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
formatter: (value) => {
|
||||
return value + " Mbps";
|
||||
},
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
},
|
||||
stroke: {
|
||||
curve: "smooth",
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "line",
|
||||
name: "Receive",
|
||||
data: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
h5SpeedtestUploadSpeedChart: {
|
||||
chartOptions: {
|
||||
chart: {
|
||||
id: "speedtest-upload-chart",
|
||||
height: 200,
|
||||
foreColor: "#e8e8e8",
|
||||
animations: {
|
||||
enabled: true,
|
||||
easing: "linear",
|
||||
dynamicAnimation: {
|
||||
speed: 300,
|
||||
},
|
||||
},
|
||||
zoom: {
|
||||
enabled: false,
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
theme: "dark",
|
||||
},
|
||||
},
|
||||
xaxis: {
|
||||
type: "category",
|
||||
categories: [""],
|
||||
labels: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
formatter: (value) => {
|
||||
return value + " Mbps";
|
||||
},
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
},
|
||||
stroke: {
|
||||
curve: "smooth",
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "line",
|
||||
name: "Receive",
|
||||
data: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,210 +1,238 @@
|
||||
<template>
|
||||
<div>
|
||||
<n-card hoverable>
|
||||
<template #header>
|
||||
服务器流量图
|
||||
</template>
|
||||
<n-grid x-gap="12" cols="1 s:1 m:1 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-gi v-for="(interfaceData, interfaceName) in interfaces">
|
||||
<n-card :title="interfaceName">
|
||||
<n-grid x-gap="12" :cols="2">
|
||||
<n-gi>
|
||||
<h3>已接收</h3>
|
||||
<span class="traffic-display">
|
||||
{{ formatBytes(interfaceData.traffic.receive, 2, true) }} /
|
||||
{{ formatBytes(interfaceData.receive) }}
|
||||
</span>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<h3>已发送</h3>
|
||||
<span class="traffic-display">
|
||||
{{ formatBytes(interfaceData.traffic.send, 2, true) }} /
|
||||
{{ formatBytes(interfaceData.send) }}
|
||||
</span>
|
||||
</n-gi>
|
||||
<n-gi span="2">
|
||||
<apexchart type="line" :options="interfaceData.chartOptions"
|
||||
:series="interfaceData.series">
|
||||
</apexchart>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
</n-gi>
|
||||
<div>
|
||||
<n-card hoverable>
|
||||
<template #header> 服务器流量图 </template>
|
||||
<n-grid x-gap="12" cols="1 s:1 m:1 l:2 xl:2 2xl:2" responsive="screen">
|
||||
<n-gi v-for="(interfaceData, interfaceName) in interfaces">
|
||||
<n-card :title="interfaceName">
|
||||
<n-grid x-gap="12" :cols="2">
|
||||
<n-gi>
|
||||
<h3>已接收</h3>
|
||||
<span class="traffic-display">
|
||||
{{ formatBytes(interfaceData.traffic.receive, 2, true) }} /
|
||||
{{ formatBytes(interfaceData.receive) }}
|
||||
</span>
|
||||
</n-gi>
|
||||
<n-gi>
|
||||
<h3>已发送</h3>
|
||||
<span class="traffic-display">
|
||||
{{ formatBytes(interfaceData.traffic.send, 2, true) }} /
|
||||
{{ formatBytes(interfaceData.send) }}
|
||||
</span>
|
||||
</n-gi>
|
||||
<n-gi span="2">
|
||||
<apexchart
|
||||
type="line"
|
||||
:options="interfaceData.chartOptions"
|
||||
:series="interfaceData.series"
|
||||
>
|
||||
</apexchart>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
</div>
|
||||
</n-card>
|
||||
</n-gi>
|
||||
</n-grid>
|
||||
</n-card>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, defineAsyncComponent } from 'vue'
|
||||
import { defineComponent, defineAsyncComponent } from "vue";
|
||||
export default defineComponent({
|
||||
components: {
|
||||
apexchart: defineAsyncComponent(() => import('vue3-apexcharts')),
|
||||
components: {
|
||||
apexchart: defineAsyncComponent(() => import("vue3-apexcharts")),
|
||||
},
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
traffic: {
|
||||
receive: null,
|
||||
send: null,
|
||||
},
|
||||
categories: [],
|
||||
refreshTimer: null,
|
||||
interfaces: {},
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
updateSeries() {
|
||||
var nowPointName =
|
||||
new Date().getHours().toString().padStart(2, "0") +
|
||||
":" +
|
||||
new Date().getMinutes().toString().padStart(2, "0") +
|
||||
":" +
|
||||
new Date().getSeconds().toString().padStart(2, "0");
|
||||
for (let interfaceName in this.interfaces) {
|
||||
let categories =
|
||||
this.interfaces[interfaceName].chartOptions.xaxis.categories;
|
||||
let receiveDatas = this.interfaces[interfaceName].series[0].data;
|
||||
let sendDatas = this.interfaces[interfaceName].series[1].data;
|
||||
let receive =
|
||||
this.interfaces[interfaceName].receive -
|
||||
this.interfaces[interfaceName].lastReceive;
|
||||
let send =
|
||||
this.interfaces[interfaceName].send -
|
||||
this.interfaces[interfaceName].lastSend;
|
||||
|
||||
this.interfaces[interfaceName].lastReceive =
|
||||
this.interfaces[interfaceName].receive;
|
||||
this.interfaces[interfaceName].lastSend =
|
||||
this.interfaces[interfaceName].send;
|
||||
this.interfaces[interfaceName].traffic.receive = receive;
|
||||
this.interfaces[interfaceName].traffic.send = send;
|
||||
receiveDatas.push(receive);
|
||||
sendDatas.push(send);
|
||||
|
||||
categories.push(nowPointName);
|
||||
this.interfaces[interfaceName].chartOptions.value = {
|
||||
xaxis: { categories: categories },
|
||||
};
|
||||
}
|
||||
},
|
||||
props: {
|
||||
wsMessage: Array
|
||||
formatBytes(bytes, decimals = 2, bandwidth = false) {
|
||||
if (bytes === 0) return "0 Bytes";
|
||||
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
const bandwidthSizes = [
|
||||
"Bps",
|
||||
"Kbps",
|
||||
"Mbps",
|
||||
"Gbps",
|
||||
"Tbps",
|
||||
"Pbs",
|
||||
"Ebps",
|
||||
"Zbps",
|
||||
"Ybps",
|
||||
];
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
if (bandwidth) {
|
||||
bytes = bytes * 10;
|
||||
return (
|
||||
parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) +
|
||||
" " +
|
||||
bandwidthSizes[i]
|
||||
);
|
||||
}
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + " " + sizes[i];
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
traffic: {
|
||||
},
|
||||
mounted() {
|
||||
setInterval(() => {
|
||||
this.updateSeries();
|
||||
}, 1000);
|
||||
this.$watch(
|
||||
() => this.wsMessage,
|
||||
() => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 100) return false;
|
||||
let interfaceName = e[1];
|
||||
let receiveTraffic = e[2];
|
||||
let sendTraffic = e[3];
|
||||
this.wsMessage.splice(i, 1);
|
||||
if (!this.interfaces.hasOwnProperty(interfaceName)) {
|
||||
this.interfaces[interfaceName] = {
|
||||
traffic: {
|
||||
receive: null,
|
||||
send: null
|
||||
},
|
||||
categories: [],
|
||||
refreshTimer: null,
|
||||
interfaces: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateSeries() {
|
||||
var nowPointName = (new Date()).getHours().toString().padStart(2, '0') + ':' +
|
||||
(new Date()).getMinutes().toString().padStart(2, '0') + ':' +
|
||||
(new Date()).getSeconds().toString().padStart(2, '0')
|
||||
for (let interfaceName in this.interfaces) {
|
||||
let categories = this.interfaces[interfaceName].chartOptions.xaxis.categories
|
||||
let receiveDatas = this.interfaces[interfaceName].series[0].data
|
||||
let sendDatas = this.interfaces[interfaceName].series[1].data
|
||||
let receive = this.interfaces[interfaceName].receive - this.interfaces[interfaceName].lastReceive
|
||||
let send = this.interfaces[interfaceName].send - this.interfaces[interfaceName].lastSend
|
||||
send: null,
|
||||
},
|
||||
receive: receiveTraffic,
|
||||
send: sendTraffic,
|
||||
lastReceive: receiveTraffic,
|
||||
lastSend: sendTraffic,
|
||||
chartOptions: {
|
||||
chart: {
|
||||
id: "interface-" + interfaceName + "-chart",
|
||||
foreColor: "#e8e8e8",
|
||||
animations: {
|
||||
enabled: true,
|
||||
easing: "linear",
|
||||
dynamicAnimation: {
|
||||
speed: 1000,
|
||||
},
|
||||
},
|
||||
zoom: {
|
||||
enabled: false,
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
theme: "dark",
|
||||
},
|
||||
},
|
||||
|
||||
this.interfaces[interfaceName].lastReceive = this.interfaces[interfaceName].receive
|
||||
this.interfaces[interfaceName].lastSend = this.interfaces[interfaceName].send
|
||||
this.interfaces[interfaceName].traffic.receive = receive
|
||||
this.interfaces[interfaceName].traffic.send = send
|
||||
receiveDatas.push(receive)
|
||||
sendDatas.push(send)
|
||||
|
||||
categories.push(nowPointName)
|
||||
this.interfaces[interfaceName].chartOptions.value = {
|
||||
xaxis: { categories: categories }
|
||||
}
|
||||
}
|
||||
},
|
||||
formatBytes(bytes, decimals = 2, bandwidth = false) {
|
||||
if (bytes === 0) return '0 Bytes';
|
||||
|
||||
const k = 1024;
|
||||
const dm = decimals < 0 ? 0 : decimals;
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
|
||||
const bandwidthSizes = ['Bps', 'Kbps', 'Mbps', 'Gbps', 'Tbps', 'Pbs', 'Ebps', 'Zbps', 'Ybps'];
|
||||
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
|
||||
if (bandwidth) {
|
||||
bytes = bytes * 10
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + bandwidthSizes[i];
|
||||
}
|
||||
return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
setInterval(() => {
|
||||
this.updateSeries()
|
||||
}, 1000)
|
||||
this.$watch(() => this.wsMessage, () => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 100) return false
|
||||
let interfaceName = e[1]
|
||||
let receiveTraffic = e[2]
|
||||
let sendTraffic = e[3]
|
||||
this.wsMessage.splice(i, 1)
|
||||
if (!this.interfaces.hasOwnProperty(interfaceName)) {
|
||||
this.interfaces[interfaceName] = {
|
||||
traffic: {
|
||||
receive: null,
|
||||
send: null
|
||||
},
|
||||
receive: receiveTraffic,
|
||||
send: sendTraffic,
|
||||
lastReceive: receiveTraffic,
|
||||
lastSend: sendTraffic,
|
||||
chartOptions: {
|
||||
chart: {
|
||||
id: "interface-" + interfaceName + "-chart",
|
||||
foreColor: '#e8e8e8',
|
||||
animations: {
|
||||
enabled: true,
|
||||
easing: 'linear',
|
||||
dynamicAnimation: {
|
||||
speed: 1000
|
||||
},
|
||||
},
|
||||
zoom: {
|
||||
enabled: false
|
||||
},
|
||||
toolbar: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
theme: 'dark'
|
||||
},
|
||||
},
|
||||
|
||||
xaxis: {
|
||||
range: 10,
|
||||
type: 'category',
|
||||
categories: [''],
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
formatter: (value) => {
|
||||
return this.formatBytes(value, 2, true)
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
x: {
|
||||
format: 'dd MMM yyyy'
|
||||
}
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false
|
||||
},
|
||||
markers: {
|
||||
size: 0
|
||||
},
|
||||
stroke: {
|
||||
curve: 'smooth'
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: 'line',
|
||||
name: 'Receive',
|
||||
data: []
|
||||
},
|
||||
{
|
||||
type: 'line',
|
||||
name: 'Send',
|
||||
data: []
|
||||
}
|
||||
]
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.interfaces[interfaceName].receive = receiveTraffic
|
||||
this.interfaces[interfaceName].send = sendTraffic
|
||||
})
|
||||
}, { immediate: true, deep: true });
|
||||
}
|
||||
})
|
||||
xaxis: {
|
||||
range: 10,
|
||||
type: "category",
|
||||
categories: [""],
|
||||
},
|
||||
yaxis: {
|
||||
labels: {
|
||||
formatter: (value) => {
|
||||
return this.formatBytes(value, 2, true);
|
||||
},
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
x: {
|
||||
format: "dd MMM yyyy",
|
||||
},
|
||||
},
|
||||
dataLabels: {
|
||||
enabled: false,
|
||||
},
|
||||
markers: {
|
||||
size: 0,
|
||||
},
|
||||
stroke: {
|
||||
curve: "smooth",
|
||||
},
|
||||
},
|
||||
series: [
|
||||
{
|
||||
type: "line",
|
||||
name: "Receive",
|
||||
data: [],
|
||||
},
|
||||
{
|
||||
type: "line",
|
||||
name: "Send",
|
||||
data: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
return;
|
||||
}
|
||||
this.interfaces[interfaceName].receive = receiveTraffic;
|
||||
this.interfaces[interfaceName].send = sendTraffic;
|
||||
});
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
<style scoped>
|
||||
h3 {
|
||||
text-align: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.traffic-display {
|
||||
text-align: center;
|
||||
display: block;
|
||||
text-align: center;
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<style>
|
||||
.apexcharts-tooltip-title,
|
||||
.apexcharts-tooltip-text {
|
||||
color: #181818;
|
||||
color: #181818;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,66 +1,97 @@
|
||||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<n-card>
|
||||
<template #header>
|
||||
网络工具
|
||||
</template>
|
||||
<n-space>
|
||||
<n-button v-show="componentConfig.utilities_ping" @click="activate('ping')">Ping</n-button>
|
||||
<n-button v-show="componentConfig.utilities_traceroute" @click="activate('traceroute')">Traceroute</n-button>
|
||||
<n-button v-show="componentConfig.utilities_iperf3" @click="activate('iperf3')">iPerf3</n-button>
|
||||
</n-space>
|
||||
<template #header> 网络工具 </template>
|
||||
<n-space>
|
||||
<n-button
|
||||
v-show="componentConfig.utilities_ping"
|
||||
@click="activate('ping')"
|
||||
>Ping</n-button
|
||||
>
|
||||
<n-button
|
||||
v-show="componentConfig.utilities_traceroute"
|
||||
@click="activate('traceroute')"
|
||||
>Traceroute</n-button
|
||||
>
|
||||
<n-button
|
||||
v-show="componentConfig.utilities_iperf3"
|
||||
@click="activate('iperf3')"
|
||||
>iPerf3</n-button
|
||||
>
|
||||
</n-space>
|
||||
</n-card>
|
||||
<n-drawer v-model:show="componentSwitch.ping" :native-scrollbar="true" :width="drawWidth" placement="right">
|
||||
<n-drawer-content title="Ping" :closable="true">
|
||||
<ping v-model:ws="ws" v-model:wsMessage="wsMessage" />
|
||||
</n-drawer-content>
|
||||
<n-drawer
|
||||
v-model:show="componentSwitch.ping"
|
||||
:native-scrollbar="true"
|
||||
:width="drawWidth"
|
||||
placement="right"
|
||||
>
|
||||
<n-drawer-content title="Ping" :closable="true">
|
||||
<ping v-model:ws="ws" v-model:wsMessage="wsMessage" />
|
||||
</n-drawer-content>
|
||||
</n-drawer>
|
||||
<n-drawer v-model:show="componentSwitch.traceroute" :native-scrollbar="true" :width="drawWidth" placement="right">
|
||||
<n-drawer-content title="Traceroute" :closable="true">
|
||||
<traceroute v-model:ws="ws" v-model:wsMessage="wsMessage" />
|
||||
</n-drawer-content>
|
||||
<n-drawer
|
||||
v-model:show="componentSwitch.traceroute"
|
||||
:native-scrollbar="true"
|
||||
:width="drawWidth"
|
||||
placement="right"
|
||||
>
|
||||
<n-drawer-content title="Traceroute" :closable="true">
|
||||
<traceroute v-model:ws="ws" v-model:wsMessage="wsMessage" />
|
||||
</n-drawer-content>
|
||||
</n-drawer>
|
||||
<n-drawer v-model:show="componentSwitch.iperf3" :native-scrollbar="true" :width="drawWidth" placement="right">
|
||||
<n-drawer-content title="iPerf3" :closable="true">
|
||||
<iperf3 v-model:ws="ws" v-model:wsMessage="wsMessage" v-model:componentConfig="componentConfig" />
|
||||
</n-drawer-content>
|
||||
<n-drawer
|
||||
v-model:show="componentSwitch.iperf3"
|
||||
:native-scrollbar="true"
|
||||
:width="drawWidth"
|
||||
placement="right"
|
||||
>
|
||||
<n-drawer-content title="iPerf3" :closable="true">
|
||||
<iperf3
|
||||
v-model:ws="ws"
|
||||
v-model:wsMessage="wsMessage"
|
||||
v-model:componentConfig="componentConfig"
|
||||
/>
|
||||
</n-drawer-content>
|
||||
</n-drawer>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, defineAsyncComponent } from 'vue'
|
||||
import { defineComponent, defineAsyncComponent } from "vue";
|
||||
export default defineComponent({
|
||||
components: {
|
||||
ping: defineAsyncComponent(() => import('./Utilities/Ping.vue')),
|
||||
traceroute: defineAsyncComponent(() => import('./Utilities/Traceroute.vue')),
|
||||
iperf3: defineAsyncComponent(() => import('./Utilities/iPerf3.vue')),
|
||||
},
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
ws: WebSocket,
|
||||
componentConfig: Object
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
drawWidth: 800,
|
||||
componentSwitch: {
|
||||
ping: false,
|
||||
traceroute: false,
|
||||
iperf3: false
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
if (window.screen.width < 800) {
|
||||
this.drawWidth = window.screen.width
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
activate(args) {
|
||||
this.host = ''
|
||||
this.componentSwitch[args] = true
|
||||
}
|
||||
components: {
|
||||
ping: defineAsyncComponent(() => import("./Utilities/Ping.vue")),
|
||||
traceroute: defineAsyncComponent(() =>
|
||||
import("./Utilities/Traceroute.vue")
|
||||
),
|
||||
iperf3: defineAsyncComponent(() => import("./Utilities/iPerf3.vue")),
|
||||
},
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
ws: WebSocket,
|
||||
componentConfig: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
drawWidth: 800,
|
||||
componentSwitch: {
|
||||
ping: false,
|
||||
traceroute: false,
|
||||
iperf3: false,
|
||||
},
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
if (window.screen.width < 800) {
|
||||
this.drawWidth = window.screen.width;
|
||||
}
|
||||
})
|
||||
</script>
|
||||
},
|
||||
methods: {
|
||||
activate(args) {
|
||||
this.host = "";
|
||||
this.componentSwitch[args] = true;
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,92 +1,101 @@
|
||||
<template>
|
||||
<n-space vertical>
|
||||
<n-input-group>
|
||||
<n-input :disabled="working" v-model:value="host" placeholder="IP Address Or Domain" @keyup.enter="ping" />
|
||||
<n-button :loading="working" type="primary" ghost @click="ping()">
|
||||
Ping
|
||||
</n-button>
|
||||
</n-input-group>
|
||||
<n-table v-show="records.length > 0" :bordered="false" :single-line="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Host</th>
|
||||
<th>TTL</th>
|
||||
<th>Latency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="record in records">
|
||||
<td>{{ record.seq }}</td>
|
||||
<td>{{ record.host }}</td>
|
||||
<td>{{ record.ttl }}</td>
|
||||
<td>{{ record.latency }} ms</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
</n-space>
|
||||
<n-space vertical>
|
||||
<n-input-group>
|
||||
<n-input
|
||||
:disabled="working"
|
||||
v-model:value="host"
|
||||
placeholder="IP Address Or Domain"
|
||||
@keyup.enter="ping"
|
||||
/>
|
||||
<n-button :loading="working" type="primary" ghost @click="ping()">
|
||||
Ping
|
||||
</n-button>
|
||||
</n-input-group>
|
||||
<n-table v-show="records.length > 0" :bordered="false" :single-line="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th>
|
||||
<th>Host</th>
|
||||
<th>TTL</th>
|
||||
<th>Latency</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="record in records">
|
||||
<td>{{ record.seq }}</td>
|
||||
<td>{{ record.host }}</td>
|
||||
<td>{{ record.ttl }}</td>
|
||||
<td>{{ record.latency }} ms</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</n-table>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineComponent, defineAsyncComponent } from 'vue'
|
||||
import { defineComponent, defineAsyncComponent } from "vue";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
ws: WebSocket
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
ws: WebSocket,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
host: "",
|
||||
working: false,
|
||||
records: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
ping() {
|
||||
if (this.working) return false;
|
||||
this.records = [];
|
||||
this.working = true;
|
||||
this.ws.send("1|" + this.host);
|
||||
let ticket = "";
|
||||
let pingProcess = this.$watch(
|
||||
() => this.wsMessage,
|
||||
(e) => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 1) return true;
|
||||
|
||||
if (ticket.length == 0 && e[2] == this.host && e.length == 4) {
|
||||
ticket = e[3];
|
||||
this.wsMessage.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == "0") {
|
||||
this.working = false;
|
||||
pingProcess();
|
||||
this.wsMessage.splice(i, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == "1") {
|
||||
if (e.length == 7) {
|
||||
this.records.push({
|
||||
host: e[3],
|
||||
seq: e[4],
|
||||
ttl: e[5],
|
||||
latency: e[6],
|
||||
});
|
||||
} else {
|
||||
this.records.push({
|
||||
host: "-",
|
||||
seq: this.records.length + 1,
|
||||
ttl: "-",
|
||||
latency: "-",
|
||||
});
|
||||
}
|
||||
this.wsMessage.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
host: '',
|
||||
working: false,
|
||||
records: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
ping() {
|
||||
if (this.working) return false;
|
||||
this.records = []
|
||||
this.working = true
|
||||
this.ws.send('1|' + this.host)
|
||||
let ticket = ''
|
||||
let pingProcess = this.$watch(() => this.wsMessage, (e) => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 1) return true
|
||||
|
||||
if (ticket.length == 0 && e[2] == this.host && e.length == 4) {
|
||||
ticket = e[3]
|
||||
this.wsMessage.splice(i, 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == '0') {
|
||||
this.working = false
|
||||
pingProcess()
|
||||
this.wsMessage.splice(i, 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == '1') {
|
||||
if (e.length == 7) {
|
||||
this.records.push({
|
||||
host: e[3],
|
||||
seq: e[4],
|
||||
ttl: e[5],
|
||||
latency: e[6]
|
||||
})
|
||||
} else {
|
||||
this.records.push({
|
||||
host: '-',
|
||||
seq: this.records.length + 1,
|
||||
ttl: '-',
|
||||
latency: '-'
|
||||
})
|
||||
}
|
||||
this.wsMessage.splice(i, 1)
|
||||
return true;
|
||||
}
|
||||
})
|
||||
}, { immediate: true, deep: true })
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,138 +1,145 @@
|
||||
<template>
|
||||
<n-space vertical>
|
||||
<n-input-group>
|
||||
<n-input :disabled="working" v-model:value="host" :style="{ width: '90%' }"
|
||||
placeholder="IP Address Or Domain" @keyup.enter="traceroute" />
|
||||
<n-button :loading="working" type="primary" ghost @click="traceroute()">
|
||||
Traceroute
|
||||
</n-button>
|
||||
</n-input-group>
|
||||
<n-table v-show="records.length > 0" :bordered="false" :single-line="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hop #</th>
|
||||
<th>Host</th>
|
||||
<th>#1</th>
|
||||
<th>#2</th>
|
||||
<th>#3</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(record, seq) in records">
|
||||
<tr v-if="record">
|
||||
<td>{{ seq }}</td>
|
||||
<td>
|
||||
<n-space vertical>
|
||||
<n-gradient-text v-show="record.host.length > 1" type="info">
|
||||
! 基于流的负载均衡已发现
|
||||
</n-gradient-text>
|
||||
<template v-for="pop in record.host">
|
||||
<span>{{ pop.dns }} ({{ pop.host }}) | {{ pop.geo }}</span>
|
||||
</template>
|
||||
</n-space>
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="record.latency[0]">
|
||||
{{ record.latency[0] }} ms
|
||||
</template>
|
||||
<template v-else>
|
||||
-
|
||||
</template>
|
||||
</td>
|
||||
<td> <template v-if="record.latency[1]">
|
||||
{{ record.latency[1] }} ms
|
||||
</template>
|
||||
<template v-else>
|
||||
-
|
||||
</template>
|
||||
</td>
|
||||
<td> <template v-if="record.latency[2]">
|
||||
{{ record.latency[2] }} ms
|
||||
</template>
|
||||
<template v-else>
|
||||
-
|
||||
</template>
|
||||
</td>
|
||||
</tr>
|
||||
<n-space vertical>
|
||||
<n-input-group>
|
||||
<n-input
|
||||
:disabled="working"
|
||||
v-model:value="host"
|
||||
:style="{ width: '90%' }"
|
||||
placeholder="IP Address Or Domain"
|
||||
@keyup.enter="traceroute"
|
||||
/>
|
||||
<n-button :loading="working" type="primary" ghost @click="traceroute()">
|
||||
Traceroute
|
||||
</n-button>
|
||||
</n-input-group>
|
||||
<n-table v-show="records.length > 0" :bordered="false" :single-line="false">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hop #</th>
|
||||
<th>Host</th>
|
||||
<th>#1</th>
|
||||
<th>#2</th>
|
||||
<th>#3</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<template v-for="(record, seq) in records">
|
||||
<tr v-if="record">
|
||||
<td>{{ seq }}</td>
|
||||
<td>
|
||||
<n-space vertical>
|
||||
<n-gradient-text v-show="record.host.length > 1" type="info">
|
||||
! 基于流的负载均衡已发现
|
||||
</n-gradient-text>
|
||||
<template v-for="pop in record.host">
|
||||
<span>{{ pop.dns }} ({{ pop.host }}) | {{ pop.geo }}</span>
|
||||
</template>
|
||||
</tbody>
|
||||
</n-table>
|
||||
</n-space>
|
||||
</n-space>
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="record.latency[0]">
|
||||
{{ record.latency[0] }} ms
|
||||
</template>
|
||||
<template v-else> - </template>
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="record.latency[1]">
|
||||
{{ record.latency[1] }} ms
|
||||
</template>
|
||||
<template v-else> - </template>
|
||||
</td>
|
||||
<td>
|
||||
<template v-if="record.latency[2]">
|
||||
{{ record.latency[2] }} ms
|
||||
</template>
|
||||
<template v-else> - </template>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</n-table>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { method } from 'lodash'
|
||||
import { defineComponent, defineAsyncComponent } from 'vue'
|
||||
import { method } from "lodash";
|
||||
import { defineComponent, defineAsyncComponent } from "vue";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
ws: WebSocket
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
ws: WebSocket,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
host: "",
|
||||
working: false,
|
||||
records: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
traceroute() {
|
||||
if (this.working) return false;
|
||||
this.records = [];
|
||||
this.working = true;
|
||||
this.ws.send("2|" + this.host);
|
||||
let ticket = "";
|
||||
let traceProcess = this.$watch(
|
||||
() => this.wsMessage,
|
||||
(e) => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 2) return true;
|
||||
|
||||
if (ticket.length == 0 && e[2] == this.host && e.length == 4) {
|
||||
ticket = e[3];
|
||||
this.wsMessage.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == "0") {
|
||||
this.working = false;
|
||||
traceProcess();
|
||||
this.wsMessage.splice(i, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == "1") {
|
||||
if (this.records[e[3]] === undefined) {
|
||||
this.records[e[3]] = {
|
||||
host: [
|
||||
{
|
||||
dns: e[4] == "0" ? "-" : e[4],
|
||||
host: e[5] == "0" ? "-" : e[5],
|
||||
geo: e[7],
|
||||
},
|
||||
],
|
||||
latency: [e[6]],
|
||||
};
|
||||
} else {
|
||||
this.records[e[3]].host.push({
|
||||
dns: e[4] == "0" ? "-" : e[4],
|
||||
host: e[5] == "0" ? "-" : e[5],
|
||||
geo: e[7],
|
||||
});
|
||||
this.records[e[3]].latency.push(e[6]);
|
||||
}
|
||||
this.records[e[3]].host.forEach((v1, k1) => {
|
||||
this.records[e[3]].host.forEach((v2, k2) => {
|
||||
if (k1 != k2 && v1.host == v2.host) {
|
||||
this.records[e[3]].host.splice(k2, 1);
|
||||
}
|
||||
});
|
||||
if (v1.dns == "-" && this.records[e[3]].host.length > 1) {
|
||||
this.records[e[3]].host.splice(k1, 1);
|
||||
}
|
||||
});
|
||||
this.wsMessage.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
host: '',
|
||||
working: false,
|
||||
records: []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
traceroute() {
|
||||
if (this.working) return false;
|
||||
this.records = []
|
||||
this.working = true
|
||||
this.ws.send('2|' + this.host)
|
||||
let ticket = ''
|
||||
let traceProcess = this.$watch(() => this.wsMessage, (e) => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 2) return true
|
||||
|
||||
if (ticket.length == 0 && e[2] == this.host && e.length == 4) {
|
||||
ticket = e[3]
|
||||
this.wsMessage.splice(i, 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == '0') {
|
||||
this.working = false
|
||||
traceProcess()
|
||||
this.wsMessage.splice(i, 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == '1') {
|
||||
if (this.records[e[3]] === undefined) {
|
||||
this.records[e[3]] = {
|
||||
host: [{
|
||||
dns: e[4] == '0' ? '-' : e[4],
|
||||
host: e[5] == '0' ? '-' : e[5],
|
||||
geo: e[7],
|
||||
}],
|
||||
latency: [e[6]]
|
||||
}
|
||||
} else {
|
||||
this.records[e[3]].host.push({
|
||||
dns: e[4] == '0' ? '-' : e[4],
|
||||
host: e[5] == '0' ? '-' : e[5],
|
||||
geo: e[7],
|
||||
})
|
||||
this.records[e[3]].latency.push(e[6])
|
||||
}
|
||||
this.records[e[3]].host.forEach((v1, k1) => {
|
||||
this.records[e[3]].host.forEach((v2, k2) => {
|
||||
if (k1 != k2 && v1.host == v2.host) {
|
||||
this.records[e[3]].host.splice(k2, 1)
|
||||
}
|
||||
})
|
||||
if (v1.dns == '-' && this.records[e[3]].host.length > 1) {
|
||||
this.records[e[3]].host.splice(k1, 1)
|
||||
}
|
||||
})
|
||||
this.wsMessage.splice(i, 1)
|
||||
return true;
|
||||
}
|
||||
})
|
||||
}, { immediate: true, deep: true })
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,102 +1,126 @@
|
||||
<template>
|
||||
<n-space vertical>
|
||||
<n-button :block="true" :loading="working" type="primary" ghost @click="startServer()">
|
||||
{{ btnText }}
|
||||
</n-button>
|
||||
<n-progress v-show="timeout != 0" style="transform: rotate(180deg)" type="line"
|
||||
:percentage="100 - TimeoutPercentage" :show-indicator="false" />
|
||||
<n-alert v-show="working && port != 0" type="default" :show-icon="false">
|
||||
iPerf3 command:
|
||||
<p v-show="componentConfig.public_ipv4">
|
||||
IPv4:<br />
|
||||
iperf3 -c {{ componentConfig.public_ipv4 }} -p {{ port }}
|
||||
</p>
|
||||
<p v-show="componentConfig.public_ipv6">
|
||||
IPv6:<br />
|
||||
iperf3 -c {{ componentConfig.public_ipv6 }} -p {{ port }}
|
||||
</p>
|
||||
</n-alert>
|
||||
<n-input autosize style="font-family: monospace;" v-show="log.length > 0" row="30" type="textarea" :value="log"
|
||||
placeholder="iPerf3 Server log" disabled />
|
||||
</n-space>
|
||||
<n-space vertical>
|
||||
<n-button
|
||||
:block="true"
|
||||
:loading="working"
|
||||
type="primary"
|
||||
ghost
|
||||
@click="startServer()"
|
||||
>
|
||||
{{ btnText }}
|
||||
</n-button>
|
||||
<n-progress
|
||||
v-show="timeout != 0"
|
||||
style="transform: rotate(180deg)"
|
||||
type="line"
|
||||
:percentage="100 - TimeoutPercentage"
|
||||
:show-indicator="false"
|
||||
/>
|
||||
<n-alert v-show="working && port != 0" type="default" :show-icon="false">
|
||||
iPerf3 command:
|
||||
<p v-show="componentConfig.public_ipv4">
|
||||
IPv4:<br />
|
||||
iperf3 -c {{ componentConfig.public_ipv4 }} -p {{ port }}
|
||||
</p>
|
||||
<p v-show="componentConfig.public_ipv6">
|
||||
IPv6:<br />
|
||||
iperf3 -c {{ componentConfig.public_ipv6 }} -p {{ port }}
|
||||
</p>
|
||||
</n-alert>
|
||||
<n-input
|
||||
autosize
|
||||
style="font-family: monospace"
|
||||
v-show="log.length > 0"
|
||||
row="30"
|
||||
type="textarea"
|
||||
:value="log"
|
||||
placeholder="iPerf3 Server log"
|
||||
disabled
|
||||
/>
|
||||
</n-space>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import { defineComponent, defineAsyncComponent } from 'vue'
|
||||
import { defineComponent, defineAsyncComponent } from "vue";
|
||||
export default defineComponent({
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
ws: WebSocket,
|
||||
componentConfig: Object
|
||||
props: {
|
||||
wsMessage: Array,
|
||||
ws: WebSocket,
|
||||
componentConfig: Object,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
btnText: "Start iPerf3 Server",
|
||||
working: false,
|
||||
log: "",
|
||||
port: 0,
|
||||
timeout: 0,
|
||||
timePass: 0,
|
||||
TimeoutPercentage: 0,
|
||||
timeoutTimer: null,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
startServer() {
|
||||
if (this.working) return false;
|
||||
this.btnText = "iPerf3 Server starting...";
|
||||
this.log = "";
|
||||
this.working = true;
|
||||
this.ws.send("4");
|
||||
let ticket = "";
|
||||
let iperfProcess = this.$watch(
|
||||
() => this.wsMessage,
|
||||
(e) => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 4) return true;
|
||||
if (ticket.length == 0 && e[1] == "1" && e.length == 3) {
|
||||
ticket = e[2];
|
||||
this.wsMessage.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == "0") {
|
||||
this.working = false;
|
||||
this.port = 0;
|
||||
this.timeout = 0;
|
||||
clearInterval(this.timeoutTimer);
|
||||
this.timePass = 0;
|
||||
iperfProcess();
|
||||
this.btnText = "Start iPerf3 Server";
|
||||
this.wsMessage.splice(i, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == "1") {
|
||||
this.port = e[3];
|
||||
this.timeout = e[4];
|
||||
this.timeoutTimer = setInterval(() => {
|
||||
this.btnText =
|
||||
"iPerf3 Server started (" +
|
||||
(this.timeout - this.timePass) +
|
||||
"s left)";
|
||||
this.timePass++;
|
||||
this.TimeoutPercentage = Math.floor(
|
||||
(this.timePass / this.timeout) * 100
|
||||
);
|
||||
}, 1000);
|
||||
this.wsMessage.splice(i, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == "2") {
|
||||
console.log(this.log);
|
||||
if (e[3].length > 0) {
|
||||
this.log = this.log + e[3];
|
||||
}
|
||||
this.wsMessage.splice(i, 1);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
{ immediate: true, deep: true }
|
||||
);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
btnText: 'Start iPerf3 Server',
|
||||
working: false,
|
||||
log: '',
|
||||
port: 0,
|
||||
timeout: 0,
|
||||
timePass: 0,
|
||||
TimeoutPercentage: 0,
|
||||
timeoutTimer: null,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
startServer() {
|
||||
if (this.working) return false;
|
||||
this.btnText = 'iPerf3 Server starting...'
|
||||
this.log = ''
|
||||
this.working = true
|
||||
this.ws.send('4')
|
||||
let ticket = ''
|
||||
let iperfProcess = this.$watch(() => this.wsMessage, (e) => {
|
||||
this.wsMessage.forEach((e, i) => {
|
||||
if (e[0] != 4) return true
|
||||
if (ticket.length == 0 && e[1] == '1' && e.length == 3) {
|
||||
ticket = e[2]
|
||||
this.wsMessage.splice(i, 1)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == '0') {
|
||||
this.working = false
|
||||
this.port = 0
|
||||
this.timeout = 0
|
||||
clearInterval(this.timeoutTimer)
|
||||
this.timePass = 0
|
||||
iperfProcess()
|
||||
this.btnText = 'Start iPerf3 Server'
|
||||
this.wsMessage.splice(i, 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == '1') {
|
||||
this.port = e[3]
|
||||
this.timeout = e[4]
|
||||
this.timeoutTimer = setInterval(() => {
|
||||
this.btnText = 'iPerf3 Server started (' + (this.timeout - this.timePass) + 's left)'
|
||||
this.timePass++
|
||||
this.TimeoutPercentage = Math.floor((this.timePass / this.timeout) * 100)
|
||||
}, 1000)
|
||||
this.wsMessage.splice(i, 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ticket == e[1] && e[2] == '2') {
|
||||
console.log(this.log)
|
||||
if (e[3].length > 0) {
|
||||
this.log = this.log + e[3]
|
||||
}
|
||||
this.wsMessage.splice(i, 1)
|
||||
return false;
|
||||
}
|
||||
})
|
||||
|
||||
}, { immediate: true, deep: true })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
</script>
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { createApp } from 'vue'
|
||||
import App from './App.vue'
|
||||
import { createApp } from "vue";
|
||||
import App from "./App.vue";
|
||||
|
||||
createApp(App).mount('#app')
|
||||
createApp(App).mount("#app");
|
||||
|
||||
@@ -1,36 +1,37 @@
|
||||
import { fileURLToPath, URL } from 'url'
|
||||
import { fileURLToPath, URL } from "url";
|
||||
|
||||
import { defineConfig } from 'vite'
|
||||
import vue from '@vitejs/plugin-vue'
|
||||
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
import vueJsx from "@vitejs/plugin-vue-jsx";
|
||||
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import { NaiveUiResolver } from 'unplugin-vue-components/resolvers'
|
||||
import Components from "unplugin-vue-components/vite";
|
||||
import { NaiveUiResolver } from "unplugin-vue-components/resolvers";
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [
|
||||
vue(),
|
||||
vueJsx(),
|
||||
Components({
|
||||
resolvers: [NaiveUiResolver()]
|
||||
})],
|
||||
resolvers: [NaiveUiResolver()],
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': fileURLToPath(new URL('./src', import.meta.url))
|
||||
}
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
server: {
|
||||
proxy: {
|
||||
'/ws': {
|
||||
target: 'ws://127.0.0.1:80',
|
||||
ws: true
|
||||
"/ws": {
|
||||
target: "ws://127.0.0.1:80",
|
||||
ws: true,
|
||||
},
|
||||
'/speedtest-static': {
|
||||
target: 'http://127.0.0.1:80',
|
||||
"/speedtest-static": {
|
||||
target: "http://127.0.0.1:80",
|
||||
},
|
||||
'/speedtest/': {
|
||||
target: 'http://127.0.0.1:80',
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
"/speedtest/": {
|
||||
target: "http://127.0.0.1:80",
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user