Merge pull request #13 from wikihost-opensource/master-cf-autofix

Apply fixes from CodeFactor
This commit is contained in:
samlm0
2022-10-19 12:50:18 +08:00
committed by GitHub
11 changed files with 1135 additions and 973 deletions

View File

@@ -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;

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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>

View File

@@ -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");

View File

@@ -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",
},
},
},
});