Skip to content

Commit

Permalink
feat: download and restart Sub-Store
Browse files Browse the repository at this point in the history
  • Loading branch information
xream committed Feb 7, 2025
1 parent d29a898 commit 6f8ed50
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 16 deletions.
68 changes: 67 additions & 1 deletion src/main/resolve/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ import { getAppConfig, getControledMihomoConfig } from '../config'
import { Worker } from 'worker_threads'
import { mihomoWorkDir, resourcesFilesDir, subStoreDir, substoreLogPath } from '../utils/dirs'
import subStoreIcon from '../../../resources/subStoreIcon.png?asset'
import { createWriteStream } from 'fs'
import { createWriteStream, existsSync, mkdirSync } from 'fs'
import { writeFile, rm, cp } from 'fs/promises'
import http from 'http'
import net from 'net'
import path from 'path'
import { nativeImage } from 'electron'
import express from 'express'
import axios from 'axios'
import AdmZip from 'adm-zip'

export let pacPort: number
export let subStorePort: number
Expand Down Expand Up @@ -135,3 +138,66 @@ export async function stopSubStoreBackendServer(): Promise<void> {
subStoreBackendWorker.terminate()
}
}

export async function downloadSubStore(): Promise<void> {
const { 'mixed-port': mixedPort = 7890 } = await getControledMihomoConfig()
const frontendDir = path.join(resourcesFilesDir(), 'sub-store-frontend')
const backendPath = path.join(resourcesFilesDir(), 'sub-store.bundle.js')
const tempDir = path.join(resourcesFilesDir(), 'temp')

try {
// 下载后端文件
const backendRes = await axios.get(
'https://github.com/sub-store-org/Sub-Store/releases/latest/download/sub-store.bundle.js',
{
responseType: 'arraybuffer',
headers: { 'Content-Type': 'application/octet-stream' },
proxy: {
protocol: 'http',
host: '127.0.0.1',
port: mixedPort
}
}
)
await writeFile(backendPath, Buffer.from(backendRes.data))

// 下载前端文件
const frontendRes = await axios.get(
'https://github.com/sub-store-org/Sub-Store-Front-End/releases/latest/download/dist.zip',
{
responseType: 'arraybuffer',
headers: { 'Content-Type': 'application/octet-stream' },
proxy: {
protocol: 'http',
host: '127.0.0.1',
port: mixedPort
}
}
)

// 创建临时目录
if (existsSync(tempDir)) {
await rm(tempDir, { recursive: true })
}
mkdirSync(tempDir, { recursive: true })

// 先解压到临时目录
const zip = new AdmZip(Buffer.from(frontendRes.data))
zip.extractAllTo(tempDir, true)

// 确保目标目录存在并清空
if (existsSync(frontendDir)) {
await rm(frontendDir, { recursive: true })
}
mkdirSync(frontendDir, { recursive: true })

// 将 dist 目录中的内容移动到目标目录
await cp(path.join(tempDir, 'dist'), frontendDir, { recursive: true })

// 清理临时目录
await rm(tempDir, { recursive: true })
} catch (error) {
console.error('下载 Sub-Store 文件失败:', error)
throw error
}
}
2 changes: 2 additions & 0 deletions src/main/utils/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import {
startSubStoreBackendServer,
stopSubStoreFrontendServer,
stopSubStoreBackendServer,
downloadSubStore,
subStoreFrontendPort,
subStorePort
} from '../resolve/server'
Expand Down Expand Up @@ -203,6 +204,7 @@ export function registerIpcMainHandlers(): void {
ipcMain.handle('stopSubStoreFrontendServer', () => ipcErrorWrapper(stopSubStoreFrontendServer)())
ipcMain.handle('startSubStoreBackendServer', () => ipcErrorWrapper(startSubStoreBackendServer)())
ipcMain.handle('stopSubStoreBackendServer', () => ipcErrorWrapper(stopSubStoreBackendServer)())
ipcMain.handle('downloadSubStore', () => ipcErrorWrapper(downloadSubStore)())

ipcMain.handle('subStorePort', () => subStorePort)
ipcMain.handle('subStoreFrontendPort', () => subStoreFrontendPort)
Expand Down
71 changes: 56 additions & 15 deletions src/renderer/src/pages/substore.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import { Button } from '@heroui/react'
import BasePage from '@renderer/components/base/base-page'
import { useAppConfig } from '@renderer/hooks/use-app-config'
import { subStoreFrontendPort, subStorePort } from '@renderer/utils/ipc'
import {
subStoreFrontendPort,
subStorePort,
startSubStoreFrontendServer,
startSubStoreBackendServer,
stopSubStoreFrontendServer,
stopSubStoreBackendServer,
downloadSubStore
} from '@renderer/utils/ipc'
import React, { useEffect, useState } from 'react'
import { HiExternalLink } from 'react-icons/hi'
import { IoMdCloudDownload } from 'react-icons/io'

const SubStore: React.FC = () => {
const { appConfig } = useAppConfig()
const { useCustomSubStore, customSubStoreUrl } = appConfig || {}
const [backendPort, setBackendPort] = useState<number | undefined>()
const [frontendPort, setFrontendPort] = useState<number | undefined>()
const [isUpdating, setIsUpdating] = useState(false)
const getPort = async (): Promise<void> => {
setBackendPort(await subStorePort())
setFrontendPort(await subStoreFrontendPort())
Expand All @@ -25,20 +35,51 @@ const SubStore: React.FC = () => {
<BasePage
title="Sub-Store"
header={
<Button
title="在浏览器中打开"
isIconOnly
size="sm"
className="app-nodrag"
variant="light"
onPress={() => {
open(
`http://127.0.0.1:${frontendPort}?api=${useCustomSubStore ? customSubStoreUrl : `http://127.0.0.1:${backendPort}`}`
)
}}
>
<HiExternalLink className="text-lg" />
</Button>
<div className="flex gap-2">
<Button
title="检查更新"
isIconOnly
size="sm"
className="app-nodrag"
variant="light"
isLoading={isUpdating}
onPress={async () => {
try {
new Notification('Sub-Store 更新中...')
setIsUpdating(true)
await downloadSubStore()
await stopSubStoreBackendServer()
await startSubStoreBackendServer()
await new Promise((resolve) => setTimeout(resolve, 1000))
setFrontendPort(0)
await stopSubStoreFrontendServer()
await startSubStoreFrontendServer()
await getPort()
new Notification('Sub-Store 更新完成')
} catch (e) {
new Notification(`Sub-Store 更新失败: ${e}`)
} finally {
setIsUpdating(false)
}
}}
>
<IoMdCloudDownload className="text-lg" />
</Button>
<Button
title="在浏览器中打开"
isIconOnly
size="sm"
className="app-nodrag"
variant="light"
onPress={() => {
open(
`http://127.0.0.1:${frontendPort}?api=${useCustomSubStore ? customSubStoreUrl : `http://127.0.0.1:${backendPort}`}`
)
}}
>
<HiExternalLink className="text-lg" />
</Button>
</div>
}
>
<iframe
Expand Down
3 changes: 3 additions & 0 deletions src/renderer/src/utils/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,9 @@ export async function startSubStoreBackendServer(): Promise<void> {
export async function stopSubStoreBackendServer(): Promise<void> {
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('stopSubStoreBackendServer'))
}
export async function downloadSubStore(): Promise<void> {
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('downloadSubStore'))
}

export async function subStorePort(): Promise<number> {
return ipcErrorWrapper(await window.electron.ipcRenderer.invoke('subStorePort'))
Expand Down

0 comments on commit 6f8ed50

Please sign in to comment.