feat: add ProxySelector component for GitHub proxy configuration and connection testing (#2185)
This commit is contained in:
@@ -2,6 +2,7 @@ import traceback
|
||||
import psutil
|
||||
import time
|
||||
import threading
|
||||
import aiohttp
|
||||
from .route import Route, Response, RouteContext
|
||||
from astrbot.core import logger
|
||||
from quart import request
|
||||
@@ -25,6 +26,7 @@ class StatRoute(Route):
|
||||
"/stat/version": ("GET", self.get_version),
|
||||
"/stat/start-time": ("GET", self.get_start_time),
|
||||
"/stat/restart-core": ("POST", self.restart_core),
|
||||
"/stat/test-ghproxy-connection": ("POST", self.test_ghproxy_connection),
|
||||
}
|
||||
self.db_helper = db_helper
|
||||
self.register_routes()
|
||||
@@ -45,11 +47,7 @@ class StatRoute(Route):
|
||||
"""将总秒数转换为时分秒组件"""
|
||||
minutes, seconds = divmod(total_seconds, 60)
|
||||
hours, minutes = divmod(minutes, 60)
|
||||
return {
|
||||
"hours": hours,
|
||||
"minutes": minutes,
|
||||
"seconds": seconds
|
||||
}
|
||||
return {"hours": hours, "minutes": minutes, "seconds": seconds}
|
||||
|
||||
def is_default_cred(self):
|
||||
username = self.config["dashboard"]["username"]
|
||||
@@ -144,3 +142,40 @@ class StatRoute(Route):
|
||||
except Exception as e:
|
||||
logger.error(traceback.format_exc())
|
||||
return Response().error(e.__str__()).__dict__
|
||||
|
||||
async def test_ghproxy_connection(self):
|
||||
"""
|
||||
测试 GitHub 代理连接是否可用。
|
||||
"""
|
||||
try:
|
||||
data = await request.get_json()
|
||||
proxy_url: str = data.get("proxy_url")
|
||||
|
||||
if not proxy_url:
|
||||
return Response().error("proxy_url is required").__dict__
|
||||
|
||||
proxy_url = proxy_url.rstrip("/")
|
||||
|
||||
test_url = f"{proxy_url}/https://github.com/AstrBotDevs/AstrBot/raw/refs/heads/master/.python-version"
|
||||
start_time = time.time()
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(
|
||||
test_url, timeout=aiohttp.ClientTimeout(total=10)
|
||||
) as response:
|
||||
if response.status == 200:
|
||||
end_time = time.time()
|
||||
_ = await response.text()
|
||||
ret = {
|
||||
"latency": round((end_time - start_time) * 1000, 2),
|
||||
}
|
||||
return Response().ok(data=ret).__dict__
|
||||
else:
|
||||
return (
|
||||
Response()
|
||||
.error(f"Failed. Status code: {response.status}")
|
||||
.__dict__
|
||||
)
|
||||
except Exception as e:
|
||||
logger.error(traceback.format_exc())
|
||||
return Response().error(f"Error: {str(e)}").__dict__
|
||||
|
||||
@@ -0,0 +1,152 @@
|
||||
<template>
|
||||
<h5>GitHub 加速</h5>
|
||||
<v-radio-group class="mt-2" v-model="radioValue" hide-details="true">
|
||||
<v-radio label="不使用 GitHub 加速" value="0"></v-radio>
|
||||
<v-radio value="1">
|
||||
<template v-slot:label>
|
||||
<span>使用 GitHub 加速</span>
|
||||
<v-btn v-if="radioValue === '1'" class="ml-2" @click="testAllProxies" size="x-small"
|
||||
variant="tonal" :loading="loadingTestingConnection">
|
||||
测试代理连通性
|
||||
</v-btn>
|
||||
</template>
|
||||
</v-radio>
|
||||
</v-radio-group>
|
||||
<div v-if="radioValue === '1'" style="margin-left: 16px;">
|
||||
<v-radio-group v-model="githubProxyRadioControl" class="mt-2" hide-details="true">
|
||||
<v-radio color="success" v-for="(proxy, idx) in githubProxies" :key="proxy" :value="idx">
|
||||
<template v-slot:label>
|
||||
<div class="d-flex align-center">
|
||||
<span class="mr-2">{{ proxy }}</span>
|
||||
<div v-if="proxyStatus[idx]">
|
||||
<v-chip
|
||||
:color="proxyStatus[idx].available ? 'success' : 'error'"
|
||||
size="x-small"
|
||||
class="mr-1">
|
||||
{{ proxyStatus[idx].available ? '可用' : '不可用' }}
|
||||
</v-chip>
|
||||
<v-chip
|
||||
v-if="proxyStatus[idx].available"
|
||||
color="info"
|
||||
size="x-small">
|
||||
{{ proxyStatus[idx].latency }}ms
|
||||
</v-chip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</v-radio>
|
||||
<v-radio color="primary" value="-1" label="自定义">
|
||||
<template v-slot:label v-if="githubProxyRadioControl === '-1'">
|
||||
<v-text-field density="compact" v-model="selectedGitHubProxy" variant="outlined"
|
||||
style="width: 100vw;" placeholder="自定义" hide-details="true">
|
||||
</v-text-field>
|
||||
</template>
|
||||
</v-radio>
|
||||
</v-radio-group>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import { useModuleI18n } from '@/i18n/composables';
|
||||
|
||||
export default {
|
||||
setup() {
|
||||
const { tm } = useModuleI18n('features/settings');
|
||||
return { tm };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
githubProxies: [
|
||||
"https://edgeone.gh-proxy.com",
|
||||
"https://hk.gh-proxy.com/",
|
||||
"https://gh-proxy.com/",
|
||||
"https://gh.llkk.cc",
|
||||
],
|
||||
githubProxyRadioControl: "0", // the index of the selected proxy
|
||||
selectedGitHubProxy: "",
|
||||
radioValue: "0", // 0: 不使用, 1: 使用
|
||||
loadingTestingConnection: false,
|
||||
testingProxies: {},
|
||||
proxyStatus: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async testSingleProxy(idx) {
|
||||
this.testingProxies[idx] = true;
|
||||
|
||||
const proxy = this.githubProxies[idx];
|
||||
|
||||
try {
|
||||
const response = await axios.post('/api/stat/test-ghproxy-connection', {
|
||||
proxy_url: proxy
|
||||
});
|
||||
console.log(response.data);
|
||||
if (response.status === 200) {
|
||||
this.proxyStatus[idx] = {
|
||||
available: true,
|
||||
latency: Math.round(response.data.data.latency)
|
||||
};
|
||||
} else {
|
||||
this.proxyStatus[idx] = {
|
||||
available: false,
|
||||
latency: 0
|
||||
};
|
||||
}
|
||||
} catch (error) {
|
||||
this.proxyStatus[idx] = {
|
||||
available: false,
|
||||
latency: 0
|
||||
};
|
||||
} finally {
|
||||
this.testingProxies[idx] = false;
|
||||
}
|
||||
},
|
||||
|
||||
async testAllProxies() {
|
||||
this.loadingTestingConnection = true;
|
||||
|
||||
const promises = this.githubProxies.map((proxy, idx) =>
|
||||
this.testSingleProxy(idx)
|
||||
);
|
||||
|
||||
await Promise.all(promises);
|
||||
this.loadingTestingConnection = false;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.selectedGitHubProxy = localStorage.getItem('selectedGitHubProxy') || "";
|
||||
this.radioValue = localStorage.getItem('githubProxyRadioValue') || "0";
|
||||
this.githubProxyRadioControl = localStorage.getItem('githubProxyRadioControl') || "0";
|
||||
},
|
||||
watch: {
|
||||
selectedGitHubProxy: function (newVal, oldVal) {
|
||||
if (!newVal) {
|
||||
newVal = ""
|
||||
}
|
||||
localStorage.setItem('selectedGitHubProxy', newVal);
|
||||
},
|
||||
radioValue: function (newVal) {
|
||||
localStorage.setItem('githubProxyRadioValue', newVal);
|
||||
if (newVal === "0") {
|
||||
this.selectedGitHubProxy = "";
|
||||
}
|
||||
},
|
||||
githubProxyRadioControl: function (newVal) {
|
||||
localStorage.setItem('githubProxyRadioControl', newVal);
|
||||
if (newVal !== "-1") {
|
||||
this.selectedGitHubProxy = this.githubProxies[newVal] || "";
|
||||
} else {
|
||||
this.selectedGitHubProxy = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.v-label {
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
</style>
|
||||
@@ -3,6 +3,7 @@ import ExtensionCard from '@/components/shared/ExtensionCard.vue';
|
||||
import AstrBotConfig from '@/components/shared/AstrBotConfig.vue';
|
||||
import ConsoleDisplayer from '@/components/shared/ConsoleDisplayer.vue';
|
||||
import ReadmeDialog from '@/components/shared/ReadmeDialog.vue';
|
||||
import ProxySelector from '@/components/shared/ProxySelector.vue';
|
||||
import axios from 'axios';
|
||||
import { useCommonStore } from '@/stores/common';
|
||||
import { useI18n, useModuleI18n } from '@/i18n/composables';
|
||||
@@ -1190,6 +1191,9 @@ onMounted(async () => {
|
||||
hide-details
|
||||
placeholder="https://github.com/username/repo"
|
||||
></v-text-field>
|
||||
<div class="mt-4">
|
||||
<ProxySelector></ProxySelector>
|
||||
</div>
|
||||
</div>
|
||||
</v-window-item>
|
||||
</v-window>
|
||||
|
||||
@@ -5,11 +5,8 @@
|
||||
<v-list lines="two">
|
||||
<v-list-subheader>{{ tm('network.title') }}</v-list-subheader>
|
||||
|
||||
<v-list-item :subtitle="tm('network.githubProxy.subtitle')" :title="tm('network.githubProxy.title')">
|
||||
|
||||
<v-combobox variant="outlined" style="width: 100%; margin-top: 16px;" v-model="selectedGitHubProxy" :items="githubProxies"
|
||||
:label="tm('network.githubProxy.label')">
|
||||
</v-combobox>
|
||||
<v-list-item>
|
||||
<ProxySelector></ProxySelector>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-subheader>{{ tm('system.title') }}</v-list-subheader>
|
||||
@@ -17,41 +14,29 @@
|
||||
<v-list-item :subtitle="tm('system.restart.subtitle')" :title="tm('system.restart.title')">
|
||||
<v-btn style="margin-top: 16px;" color="error" @click="restartAstrBot">{{ tm('system.restart.button') }}</v-btn>
|
||||
</v-list-item>
|
||||
|
||||
|
||||
|
||||
|
||||
</v-list>
|
||||
|
||||
</div>
|
||||
|
||||
<WaitingForRestart ref="wfr"></WaitingForRestart>
|
||||
|
||||
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import axios from 'axios';
|
||||
import WaitingForRestart from '@/components/shared/WaitingForRestart.vue';
|
||||
import ProxySelector from '@/components/shared/ProxySelector.vue';
|
||||
import { useModuleI18n } from '@/i18n/composables';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
WaitingForRestart,
|
||||
ProxySelector,
|
||||
},
|
||||
setup() {
|
||||
const { tm } = useModuleI18n('features/settings');
|
||||
return { tm };
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
githubProxies: [
|
||||
"https://gh.llkk.cc",
|
||||
"https://gitproxy.click",
|
||||
],
|
||||
selectedGitHubProxy: "",
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
restartAstrBot() {
|
||||
axios.post('/api/stat/restart-core').then(() => {
|
||||
@@ -59,16 +44,5 @@ export default {
|
||||
})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.selectedGitHubProxy = localStorage.getItem('selectedGitHubProxy') || "";
|
||||
},
|
||||
watch: {
|
||||
selectedGitHubProxy: function (newVal, oldVal) {
|
||||
if (!newVal) {
|
||||
newVal = ""
|
||||
}
|
||||
localStorage.setItem('selectedGitHubProxy', newVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user