feat(config): 重构镜像源配置管理

This commit is contained in:
2025-08-13 21:02:49 +08:00
parent 95126a85d8
commit 2237dba3c5
12 changed files with 575 additions and 70 deletions

View File

@@ -203,7 +203,7 @@ export async function downloadPython(appRoot: string, mirror = 'ustc'): Promise<
// Python 3.12.0嵌入式版本应该大约30MB如果小于5MB可能是无效文件
if (stats.size < 5 * 1024 * 1024) { // 5MB
fs.unlinkSync(zipPath) // 删除无效文件
throw new Error(`Python下载文件大小异常: ${stats.size} bytes (${(stats.size / 1024).toFixed(2)} KB),可能是镜像站返回的错误页面或无效文件`)
throw new Error(`Python下载文件大小异常: ${stats.size} bytes (${(stats.size / 1024).toFixed(2)} KB),可能是镜像站返回的错误页面或无效文件。请选择一个其他可用镜像源进行下载!`)
}
if (mainWindow) {

100
frontend/src/api/mirrors.ts Normal file
View File

@@ -0,0 +1,100 @@
/**
* 镜像源 API 接口
* 用于从后端获取最新的镜像源配置
*/
import { OpenAPI } from '@/api'
import type { MirrorConfig } from '@/config/mirrors'
export interface MirrorApiResponse {
git?: MirrorConfig[]
python?: MirrorConfig[]
pip?: MirrorConfig[]
apiEndpoints?: {
local?: string
production?: string
proxy?: string
}
downloadLinks?: {
[category: string]: {
[key: string]: string
}
}
}
/**
* 获取镜像源配置
*/
export async function fetchMirrorConfig(): Promise<MirrorApiResponse> {
try {
const response = await fetch(`${OpenAPI.BASE}/api/mirrors`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`)
}
return await response.json()
} catch (error) {
console.warn('获取镜像源配置失败,使用默认配置:', error)
throw error
}
}
/**
* 测试镜像源连通性
*/
export async function testMirrorConnectivity(url: string, timeout: number = 5000): Promise<{
success: boolean
speed: number
error?: string
}> {
try {
const startTime = Date.now()
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), timeout)
const response = await fetch(url, {
method: 'HEAD',
signal: controller.signal,
cache: 'no-cache',
mode: 'no-cors' // 避免 CORS 问题
})
clearTimeout(timeoutId)
const speed = Date.now() - startTime
return {
success: true,
speed
}
} catch (error) {
return {
success: false,
speed: 9999,
error: error instanceof Error ? error.message : String(error)
}
}
}
/**
* 批量测试镜像源
*/
export async function batchTestMirrors(mirrors: MirrorConfig[]): Promise<MirrorConfig[]> {
const promises = mirrors.map(async (mirror) => {
const result = await testMirrorConnectivity(mirror.url)
return {
...mirror,
speed: result.speed
}
})
const results = await Promise.all(promises)
// 按速度排序
return results.sort((a, b) => (a.speed || 9999) - (b.speed || 9999))
}

View File

@@ -41,6 +41,7 @@
import { ref, onMounted } from 'vue'
import { createComponentLogger } from '@/utils/logger'
import { getConfig } from '@/utils/config'
import { getMirrorUrl } from '@/config/mirrors'
import router from '@/router'
const logger = createComponentLogger('AutoMode')
@@ -58,6 +59,9 @@ const progress = ref(0)
const progressText = ref('')
const progressStatus = ref<'normal' | 'exception' | 'success'>('normal')
// 状态:控制是否取消自动启动
const aborted = ref(false)
// 状态:控制弹窗显隐
const forceEnterVisible = ref(false)
@@ -74,6 +78,7 @@ function handleForceEnterConfirm() {
// 事件处理
function handleSwitchToManual() {
aborted.value = true // 设置中断
props.onSwitchToManual()
}
@@ -82,12 +87,14 @@ async function startAutoProcess() {
try {
// 获取配置中保存的镜像源设置
const config = await getConfig()
if (aborted.value) return
progressText.value = '检查Git仓库更新...'
progress.value = 20
// 检查Git仓库是否有更新
const hasUpdate = await checkGitUpdate()
if (aborted.value) return
if (hasUpdate) {
progressText.value = '发现更新,正在更新代码...'
@@ -96,6 +103,7 @@ async function startAutoProcess() {
// 使用配置中保存的Git镜像源
const gitMirrorUrl = getGitMirrorUrl(config.selectedGitMirror)
const result = await window.electronAPI.updateBackend(gitMirrorUrl)
if (aborted.value) return
if (!result.success) {
throw new Error(`代码更新失败: ${result.error}`)
}
@@ -108,6 +116,7 @@ async function startAutoProcess() {
// 先尝试使用初始化时的镜像源
let pipMirror = config.selectedPipMirror || 'tsinghua'
let pipResult = await window.electronAPI.installDependencies(pipMirror)
if (aborted.value) return
// 如果初始化时的镜像源不通,让用户重新选择
if (!pipResult.success) {
@@ -127,6 +136,7 @@ async function startAutoProcess() {
progressText.value = '启动后端服务...'
progress.value = 80
await startBackendService()
if (aborted.value) return
progressText.value = '启动完成!'
progress.value = 100
@@ -167,16 +177,7 @@ async function checkGitUpdate(): Promise<boolean> {
// 根据镜像源key获取对应的URL
function getGitMirrorUrl(mirrorKey: string): string {
const mirrors = {
github: 'https://github.com/DLmaster361/AUTO_MAA.git',
ghfast: 'https://ghfast.top/https://github.com/DLmaster361/AUTO_MAA.git',
ghproxy_cloudflare: 'https://gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git.git',
ghproxy_hongkong: 'https://hk.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git.git',
ghproxy_fastly: 'https://cdn.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git.git',
ghproxy_edgeone: 'https://edgeone.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git.git'
}
return mirrors[mirrorKey as keyof typeof mirrors] || mirrors.github
return getMirrorUrl('git', mirrorKey)
}
// 启动后端服务
@@ -189,6 +190,7 @@ async function startBackendService() {
// 组件挂载时开始自动流程
onMounted(() => {
aborted.value = false
startAutoProcess()
})
</script>

View File

@@ -50,14 +50,9 @@ defineProps<{
backendExists: boolean
}>()
const gitMirrors = ref<Mirror[]>([
{ key: 'github', name: 'GitHub 官方', url: 'https://github.com/DLmaster361/AUTO_MAA.git', speed: null },
{ key: 'ghfast', name: 'ghfast 镜像', url: 'https://ghfast.top/https://github.com/DLmaster361/AUTO_MAA.git', speed: null },
{ key: 'ghproxy_cloudflare', name: 'gh-proxy Cloudflare 全球加速', url: 'https://gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git.git', speed: null },
{ key: 'ghproxy_hongkong', name: 'gh-proxy 香港节点(大陆优化)', url: 'https://hk.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git.git', speed: null },
{ key: 'ghproxy_fastly', name: 'gh-proxy Fastly CDN', url: 'https://cdn.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git.git', speed: null },
{ key: 'ghproxy_edgeone', name: 'gh-proxy EdgeOne 全球加速', url: 'https://edgeone.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git.git', speed: null }
])
import { GIT_MIRRORS } from '@/config/mirrors'
const gitMirrors = ref<Mirror[]>(GIT_MIRRORS)
const selectedGitMirror = ref('github')

View File

@@ -46,12 +46,9 @@ interface Mirror {
speed: number | null
}
const pipMirrors = ref<Mirror[]>([
{ key: 'official', name: 'PyPI 官方', url: 'https://pypi.org/simple/', speed: null },
{ key: 'tsinghua', name: '清华大学', url: 'https://pypi.tuna.tsinghua.edu.cn/simple/', speed: null },
{ key: 'aliyun', name: '阿里云', url: 'https://mirrors.aliyun.com/pypi/simple/', speed: null },
{ key: 'ustc', name: '中科大', url: 'https://pypi.mirrors.ustc.edu.cn/simple/', speed: null },
])
import { PIP_MIRRORS } from '@/config/mirrors'
const pipMirrors = ref<Mirror[]>(PIP_MIRRORS)
const selectedPipMirror = ref('tsinghua')
const testingPipSpeed = ref(false)

View File

@@ -14,12 +14,12 @@
</div>
<div v-else class="already-installed">
<a-result status="success" title="Git已成功安装无需继续安装" />
<div class="reinstall-section">
<a-button type="primary" danger @click="handleForceReinstall" :loading="reinstalling">
{{ reinstalling ? '正在重新安装...' : '强制重新安装' }}
</a-button>
<p class="reinstall-note">点击此按钮将删除现有Git环境并重新安装</p>
</div>
<!-- <div class="reinstall-section">-->
<!-- <a-button type="primary" danger @click="handleForceReinstall" :loading="reinstalling">-->
<!-- {{ reinstalling ? '正在重新安装...' : '强制重新安装' }}-->
<!-- </a-button>-->
<!-- <p class="reinstall-note">点击此按钮将删除现有Git环境并重新安装</p>-->
<!-- </div>-->
</div>
</div>
</template>

View File

@@ -28,15 +28,15 @@
<a-step title="启动服务" description="启动后端服务" />
</a-steps>
<!-- 全局进度条 -->
<div v-if="isProcessing" class="global-progress">
<a-progress
:percent="globalProgress"
:status="globalProgressStatus"
:show-info="true"
/>
<div class="progress-text">{{ progressText }}</div>
</div>
<!-- &lt;!&ndash; 全局进度条 &ndash;&gt;-->
<!-- <div v-if="isProcessing" class="global-progress">-->
<!-- <a-progress -->
<!-- :percent="globalProgress" -->
<!-- :status="globalProgressStatus"-->
<!-- :show-info="true"-->
<!-- />-->
<!-- <div class="progress-text">{{ progressText }}</div>-->
<!-- </div>-->
<div class="step-content">
<!-- 步骤 0: 主题设置 -->
@@ -94,20 +94,21 @@
</a-button>
</div>
<div v-if="errorMessage" class="error-message">
<a-alert
:message="errorMessage"
type="error"
show-icon
closable
@close="errorMessage = ''"
/>
</div>
<!-- <div v-if="errorMessage" class="error-message">-->
<!-- <a-alert -->
<!-- :message="errorMessage" -->
<!-- type="error" -->
<!-- show-icon -->
<!-- closable-->
<!-- @close="errorMessage = ''"-->
<!-- />-->
<!-- </div>-->
</div>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'
import { ref, computed, watch } from 'vue'
import { message } from 'ant-design-vue'
import { createComponentLogger } from '@/utils/logger'
import { saveConfig } from '@/utils/config'
import ThemeStep from './ThemeStep.vue'
@@ -473,6 +474,15 @@ defineExpose({
currentStep,
handleDownloadProgress
})
// 监听 errorMessage一旦有内容就弹窗
watch(errorMessage, (val) => {
if (val) {
message.error(val)
// 弹窗后可选:自动清空 errorMessage
// errorMessage.value = ''
}
})
</script>
<style scoped>

View File

@@ -15,12 +15,12 @@
</div>
<div v-else class="already-installed">
<a-result status="success" title="pip已成功安装无需继续安装" />
<div class="reinstall-section">
<a-button type="primary" danger @click="handleForceReinstall" :loading="reinstalling">
{{ reinstalling ? '正在重新安装...' : '强制重新安装' }}
</a-button>
<p class="reinstall-note">点击此按钮将删除现有pip环境并重新安装</p>
</div>
<!-- <div class="reinstall-section">-->
<!-- <a-button type="primary" danger @click="handleForceReinstall" :loading="reinstalling">-->
<!-- {{ reinstalling ? '正在重新安装...' : '强制重新安装' }}-->
<!-- </a-button>-->
<!-- <p class="reinstall-note">点击此按钮将删除现有pip环境并重新安装</p>-->
<!-- </div>-->
</div>
</div>
</template>

View File

@@ -29,12 +29,12 @@
</div>
<div v-else class="already-installed">
<a-result status="success" title="Python已成功安装无需继续安装" />
<div class="reinstall-section">
<a-button type="primary" danger @click="handleForceReinstall" :loading="reinstalling">
{{ reinstalling ? '正在重新安装...' : '强制重新安装' }}
</a-button>
<p class="reinstall-note">点击此按钮将删除现有Python环境并重新安装</p>
</div>
<!-- <div class="reinstall-section">-->
<!-- <a-button type="primary" danger @click="handleForceReinstall" :loading="reinstalling">-->
<!-- {{ reinstalling ? '正在重新安装...' : '强制重新安装' }}-->
<!-- </a-button>-->
<!-- <p class="reinstall-note">点击此按钮将删除现有Python环境并重新安装</p>-->
<!-- </div>-->
</div>
</div>
</template>
@@ -54,13 +54,9 @@ const props = defineProps<{
pythonInstalled: boolean
}>()
const pythonMirrors = ref<Mirror[]>([
{ key: 'official', name: 'Python 官方', url: 'https://www.python.org/ftp/python/3.13.0/', speed: null },
{ key: 'tsinghua', name: '清华 TUNA 镜像', url: 'https://mirrors.tuna.tsinghua.edu.cn/python/3.13.0/', speed: null },
{ key: 'ustc', name: '中科大镜像', url: 'https://mirrors.ustc.edu.cn/python/3.13.0/', speed: null },
{ key: 'huawei', name: '华为云镜像', url: 'https://mirrors.huaweicloud.com/repository/toolkit/python/3.13.0/', speed: null },
{ key: 'aliyun', name: '阿里云镜像', url: 'https://mirrors.aliyun.com/python-release/windows/', speed: null }
])
import { PYTHON_MIRRORS } from '@/config/mirrors'
const pythonMirrors = ref<Mirror[]>(PYTHON_MIRRORS)
const selectedPythonMirror = ref('tsinghua')
const testingSpeed = ref(false)

View File

@@ -0,0 +1,216 @@
/**
* 镜像源和下载链接配置文件
* 集中管理所有下载用到的链接,方便后续通过接口动态配置
*/
export interface MirrorConfig {
key: string
name: string
url: string
speed?: number | null
}
export interface MirrorCategory {
[key: string]: MirrorConfig[]
}
/**
* Git 仓库镜像源配置
*/
export const GIT_MIRRORS: MirrorConfig[] = [
{
key: 'github',
name: 'GitHub 官方',
url: 'https://github.com/DLmaster361/AUTO_MAA.git',
speed: null
},
{
key: 'ghfast',
name: 'ghfast 镜像',
url: 'https://ghfast.top/https://github.com/DLmaster361/AUTO_MAA.git',
speed: null
},
{
key: 'ghproxy_cloudflare',
name: 'gh-proxy (Cloudflare加速)',
url: 'https://gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
speed: null
},
{
key: 'ghproxy_hongkong',
name: 'gh-proxy (香港节点加速)',
url: 'https://hk.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
speed: null
},
{
key: 'ghproxy_fastly',
name: 'gh-proxy (Fastly CDN加速)',
url: 'https://cdn.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
speed: null
},
{
key: 'ghproxy_edgeone',
name: 'gh-proxy (EdgeOne加速',
url: 'https://edgeone.gh-proxy.com/https://github.com/DLmaster361/AUTO_MAA.git',
speed: null
}
]
/**
* Python 下载镜像源配置3.12.0 embed版本
*/
export const PYTHON_MIRRORS: MirrorConfig[] = [
{
key: 'official',
name: 'Python 官方',
url: 'https://www.python.org/ftp/python/3.12.0/python-3.12.0-embed-amd64.zip',
speed: null
},
{
key: 'tsinghua',
name: '清华 TUNA 镜像',
url: 'https://mirrors.tuna.tsinghua.edu.cn/python/3.12.0/python-3.12.0-embed-amd64.zip',
speed: null
},
{
key: 'ustc',
name: '中科大镜像',
url: 'https://mirrors.ustc.edu.cn/python/3.12.0/python-3.12.0-embed-amd64.zip',
speed: null
},
{
key: 'huawei',
name: '华为云镜像',
url: 'https://mirrors.huaweicloud.com/repository/toolkit/python/3.12.0/python-3.12.0-embed-amd64.zip',
speed: null
},
{
key: 'aliyun',
name: '阿里云镜像',
url: 'https://mirrors.aliyun.com/python-release/windows/python-3.12.0-embed-amd64.zip',
speed: null
}
]
/**
* PyPI pip 镜像源配置
*/
export const PIP_MIRRORS: MirrorConfig[] = [
{
key: 'official',
name: 'PyPI 官方',
url: 'https://pypi.org/simple/',
speed: null
},
{
key: 'tsinghua',
name: '清华大学',
url: 'https://pypi.tuna.tsinghua.edu.cn/simple/',
speed: null
},
{
key: 'ustc',
name: '中科大',
url: 'https://pypi.mirrors.ustc.edu.cn/simple/',
speed: null
},
{
key: 'aliyun',
name: '阿里云',
url: 'https://mirrors.aliyun.com/pypi/simple/',
speed: null
},
{
key: 'douban',
name: '豆瓣',
url: 'https://pypi.douban.com/simple/',
speed: null
}
]
/**
* API 服务端点配置
*/
export const API_ENDPOINTS = {
// 本地开发服务器
local: 'http://localhost:8000',
// WebSocket连接基础URL
websocket: 'ws://localhost:8000',
// 代理服务器示例
proxy: 'http://127.0.0.1:7890'
}
/**
* 自建下载站链接配置
*/
export const DOWNLOAD_LINKS = {
// get-pip.py 下载链接
getPip: 'http://221.236.27.82:10197/d/AUTO_MAA/get-pip.py',
// Git 客户端下载链接
git: 'http://221.236.27.82:10197/d/AUTO_MAA/git.zip'
}
/**
* 所有镜像源配置的集合
*/
export const ALL_MIRRORS: MirrorCategory = {
git: GIT_MIRRORS,
python: PYTHON_MIRRORS,
pip: PIP_MIRRORS
}
/**
* 根据类型获取镜像源配置
*/
export function getMirrorsByType(type: keyof MirrorCategory): MirrorConfig[] {
return ALL_MIRRORS[type] || []
}
/**
* 根据类型和key获取特定镜像源URL
*/
export function getMirrorUrl(type: keyof MirrorCategory, key: string): string {
const mirrors = getMirrorsByType(type)
const mirror = mirrors.find(m => m.key === key)
return mirror?.url || mirrors[0]?.url || ''
}
/**
* 获取默认镜像源(通常是第一个)
*/
export function getDefaultMirror(type: keyof MirrorCategory): MirrorConfig | null {
const mirrors = getMirrorsByType(type)
return mirrors.length > 0 ? mirrors[0] : null
}
/**
* 更新镜像源速度测试结果
*/
export function updateMirrorSpeed(type: keyof MirrorCategory, key: string, speed: number): void {
const mirrors = getMirrorsByType(type)
const mirror = mirrors.find(m => m.key === key)
if (mirror) {
mirror.speed = speed
}
}
/**
* 根据速度排序镜像源
*/
export function sortMirrorsBySpeed(mirrors: MirrorConfig[]): MirrorConfig[] {
return [...mirrors].sort((a, b) => {
const speedA = a.speed === null ? 9999 : a.speed
const speedB = b.speed === null ? 9999 : b.speed
return speedA - speedB
})
}
/**
* 获取最快的镜像源
*/
export function getFastestMirror(type: keyof MirrorCategory): MirrorConfig | null {
const mirrors = getMirrorsByType(type)
const sortedMirrors = sortMirrorsBySpeed(mirrors)
return sortedMirrors.find(m => m.speed !== null && m.speed !== 9999) || null
}

View File

@@ -13,8 +13,10 @@ import 'dayjs/locale/zh-cn'
// 配置dayjs中文本地化
dayjs.locale('zh-cn')
import { API_ENDPOINTS } from '@/config/mirrors'
// 配置API基础URL
OpenAPI.BASE = 'http://localhost:8000'
OpenAPI.BASE = API_ENDPOINTS.local
// 创建应用实例
const app = createApp(App)

View File

@@ -0,0 +1,187 @@
/**
* 镜像源管理工具
* 提供动态获取和更新镜像源配置的功能
*/
import {
ALL_MIRRORS,
API_ENDPOINTS,
DOWNLOAD_LINKS,
type MirrorConfig,
type MirrorCategory,
getMirrorUrl,
updateMirrorSpeed,
sortMirrorsBySpeed,
getFastestMirror
} from '@/config/mirrors'
/**
* 镜像源管理器类
*/
export class MirrorManager {
private static instance: MirrorManager
private mirrorConfigs: MirrorCategory = { ...ALL_MIRRORS }
private apiEndpoints = { ...API_ENDPOINTS }
private downloadLinks = { ...DOWNLOAD_LINKS }
private constructor() {}
/**
* 获取单例实例
*/
static getInstance(): MirrorManager {
if (!MirrorManager.instance) {
MirrorManager.instance = new MirrorManager()
}
return MirrorManager.instance
}
/**
* 获取指定类型的镜像源列表
*/
getMirrors(type: keyof MirrorCategory): MirrorConfig[] {
return this.mirrorConfigs[type] || []
}
/**
* 获取镜像源URL
*/
getMirrorUrl(type: keyof MirrorCategory, key: string): string {
return getMirrorUrl(type, key)
}
/**
* 更新镜像源速度
*/
updateMirrorSpeed(type: keyof MirrorCategory, key: string, speed: number): void {
updateMirrorSpeed(type, key, speed)
}
/**
* 获取最快的镜像源
*/
getFastestMirror(type: keyof MirrorCategory): MirrorConfig | null {
return getFastestMirror(type)
}
/**
* 按速度排序镜像源
*/
sortMirrorsBySpeed(mirrors: MirrorConfig[]): MirrorConfig[] {
return sortMirrorsBySpeed(mirrors)
}
/**
* 测试镜像源速度
*/
async testMirrorSpeed(url: string, timeout: number = 5000): Promise<number> {
try {
const startTime = Date.now()
const controller = new AbortController()
const timeoutId = setTimeout(() => controller.abort(), timeout)
const response = await fetch(url, {
method: 'HEAD',
signal: controller.signal,
cache: 'no-cache'
})
clearTimeout(timeoutId)
if (response.ok) {
return Date.now() - startTime
} else {
return 9999 // 请求失败
}
} catch (error) {
return 9999 // 超时或网络错误
}
}
/**
* 批量测试镜像源速度
*/
async testAllMirrorSpeeds(type: keyof MirrorCategory): Promise<MirrorConfig[]> {
const mirrors = this.getMirrors(type)
const promises = mirrors.map(async (mirror) => {
const speed = await this.testMirrorSpeed(mirror.url)
this.updateMirrorSpeed(type, mirror.key, speed)
return { ...mirror, speed }
})
const results = await Promise.all(promises)
return this.sortMirrorsBySpeed(results)
}
/**
* 获取API端点
*/
getApiEndpoint(key: keyof typeof API_ENDPOINTS): string {
return this.apiEndpoints[key]
}
/**
* 获取下载链接
*/
getDownloadLink(key: keyof typeof DOWNLOAD_LINKS): string {
return this.downloadLinks[key] || ''
}
/**
* 动态更新镜像源配置用于从API获取最新配置
*/
updateMirrorConfig(type: keyof MirrorCategory, mirrors: MirrorConfig[]): void {
this.mirrorConfigs[type] = mirrors
}
/**
* 动态更新API端点配置
*/
updateApiEndpoints(endpoints: Partial<typeof API_ENDPOINTS>): void {
this.apiEndpoints = { ...this.apiEndpoints, ...endpoints }
}
/**
* 从远程API获取镜像源配置
*/
async fetchMirrorConfigFromApi(apiUrl: string): Promise<void> {
try {
const response = await fetch(`${apiUrl}/api/mirrors`)
if (response.ok) {
const config = await response.json()
// 更新各类镜像源配置
if (config.git) this.updateMirrorConfig('git', config.git)
if (config.python) this.updateMirrorConfig('python', config.python)
if (config.pip) this.updateMirrorConfig('pip', config.pip)
// 更新API端点
if (config.apiEndpoints) this.updateApiEndpoints(config.apiEndpoints)
console.log('镜像源配置已从API更新')
}
} catch (error) {
console.warn('从API获取镜像源配置失败:', error)
}
}
/**
* 获取所有镜像源配置(用于导出或备份)
*/
getAllConfigs() {
return {
mirrors: this.mirrorConfigs,
apiEndpoints: this.apiEndpoints,
downloadLinks: this.downloadLinks
}
}
}
// 导出单例实例
export const mirrorManager = MirrorManager.getInstance()
// 导出便捷函数
export const getMirrors = (type: keyof MirrorCategory) => mirrorManager.getMirrors(type)
export const getMirrorUrlByManager = (type: keyof MirrorCategory, key: string) => mirrorManager.getMirrorUrl(type, key)
export const testMirrorSpeed = (url: string, timeout?: number) => mirrorManager.testMirrorSpeed(url, timeout)
export const testAllMirrorSpeeds = (type: keyof MirrorCategory) => mirrorManager.testAllMirrorSpeeds(type)