2024-11-23 12:56:57 +08:00

146 lines
4.6 KiB
TypeScript

import { exec, execFile, execSync, spawn } from 'child_process'
import { app, dialog, nativeTheme, shell } from 'electron'
import { readFile } from 'fs/promises'
import path from 'path'
import { promisify } from 'util'
import {
dataDir,
exePath,
mihomoCorePath,
overridePath,
profilePath,
resourcesDir,
resourcesFilesDir,
taskDir
} from '../utils/dirs'
import { copyFileSync, writeFileSync } from 'fs'
export function getFilePath(ext: string[]): string[] | undefined {
return dialog.showOpenDialogSync({
title: '选择订阅文件',
filters: [{ name: `${ext} file`, extensions: ext }],
properties: ['openFile']
})
}
export async function readTextFile(filePath: string): Promise<string> {
return await readFile(filePath, 'utf8')
}
export function openFile(type: 'profile' | 'override', id: string, ext?: 'yaml' | 'js'): void {
if (type === 'profile') {
shell.openPath(profilePath(id))
}
if (type === 'override') {
shell.openPath(overridePath(id, ext || 'js'))
}
}
export async function openUWPTool(): Promise<void> {
const execFilePromise = promisify(execFile)
const uwpToolPath = path.join(resourcesDir(), 'files', 'enableLoopback.exe')
await execFilePromise(uwpToolPath)
}
export async function setupFirewall(): Promise<void> {
const execPromise = promisify(exec)
const removeCommand = `
Remove-NetFirewallRule -DisplayName "mihomo" -ErrorAction SilentlyContinue
Remove-NetFirewallRule -DisplayName "mihomo-alpha" -ErrorAction SilentlyContinue
Remove-NetFirewallRule -DisplayName "Mihomo Party" -ErrorAction SilentlyContinue
`
const createCommand = `
New-NetFirewallRule -DisplayName "mihomo" -Direction Inbound -Action Allow -Program "${mihomoCorePath('mihomo')}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
New-NetFirewallRule -DisplayName "mihomo-alpha" -Direction Inbound -Action Allow -Program "${mihomoCorePath('mihomo-alpha')}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
New-NetFirewallRule -DisplayName "Mihomo Party" -Direction Inbound -Action Allow -Program "${exePath()}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
`
if (process.platform === 'win32') {
await execPromise(removeCommand, { shell: 'powershell' })
await execPromise(createCommand, { shell: 'powershell' })
}
}
export function setNativeTheme(theme: 'system' | 'light' | 'dark'): void {
nativeTheme.themeSource = theme
}
const elevateTaskXml = `<?xml version="1.0" encoding="UTF-16"?>
<Task version="1.2" xmlns="http://schemas.microsoft.com/windows/2004/02/mit/task">
<Triggers />
<Principals>
<Principal id="Author">
<LogonType>InteractiveToken</LogonType>
<RunLevel>HighestAvailable</RunLevel>
</Principal>
</Principals>
<Settings>
<MultipleInstancesPolicy>Parallel</MultipleInstancesPolicy>
<DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>
<StopIfGoingOnBatteries>false</StopIfGoingOnBatteries>
<AllowHardTerminate>false</AllowHardTerminate>
<StartWhenAvailable>false</StartWhenAvailable>
<RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>
<IdleSettings>
<StopOnIdleEnd>false</StopOnIdleEnd>
<RestartOnIdle>false</RestartOnIdle>
</IdleSettings>
<AllowStartOnDemand>true</AllowStartOnDemand>
<Enabled>true</Enabled>
<Hidden>false</Hidden>
<RunOnlyIfIdle>false</RunOnlyIfIdle>
<WakeToRun>false</WakeToRun>
<ExecutionTimeLimit>PT0S</ExecutionTimeLimit>
<Priority>3</Priority>
</Settings>
<Actions Context="Author">
<Exec>
<Command>"${path.join(taskDir(), `mihomo-party-run.exe`)}"</Command>
<Arguments>"${exePath()}"</Arguments>
</Exec>
</Actions>
</Task>
`
export function createElevateTask(): void {
const taskFilePath = path.join(taskDir(), `mihomo-party-run.xml`)
writeFileSync(taskFilePath, Buffer.from(`\ufeff${elevateTaskXml}`, 'utf-16le'))
copyFileSync(
path.join(resourcesFilesDir(), 'mihomo-party-run.exe'),
path.join(taskDir(), 'mihomo-party-run.exe')
)
execSync(
`%SystemRoot%\\System32\\schtasks.exe /create /tn "mihomo-party-run" /xml "${taskFilePath}" /f`
)
}
export function resetAppConfig(): void {
if (process.platform === 'win32') {
spawn(
'cmd',
[
'/C',
`"timeout /t 2 /nobreak >nul && rmdir /s /q "${dataDir()}" && start "" "${exePath()}""`
],
{
shell: true,
detached: true
}
).unref()
} else {
const script = `while kill -0 ${process.pid} 2>/dev/null; do
sleep 0.1
done
rm -rf '${dataDir()}'
${process.argv.join(' ')} & disown
exit
`
spawn('sh', ['-c', `"${script}"`], {
shell: true,
detached: true,
stdio: 'ignore'
})
}
app.quit()
}