Skip to content

Commit 160537b

Browse files
author
pompurin404
committed
support change data dir
1 parent fe2f4fa commit 160537b

File tree

14 files changed

+152
-90
lines changed

14 files changed

+152
-90
lines changed

src/main/config/controledMihomo.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { controledMihomoConfigPath } from '../utils/dirs'
22
import { readFile, writeFile } from 'fs/promises'
33
import yaml from 'yaml'
44
import { getAxios, startMihomoMemory, startMihomoTraffic } from '../core/mihomoApi'
5-
import { generateProfile } from '../resolve/factory'
5+
import { generateProfile } from '../core/factory'
66
import { getAppConfig } from './app'
77
import { defaultControledMihomoConfig } from '../utils/template'
88

src/main/resolve/factory.ts src/main/core/factory.ts

+9
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
import { mihomoWorkConfigPath } from '../utils/dirs'
99
import yaml from 'yaml'
1010
import fs from 'fs'
11+
import { readFile } from 'fs/promises'
1112

1213
export async function generateProfile(): Promise<void> {
1314
const { current } = await getProfileConfig()
@@ -59,3 +60,11 @@ function runOverrideScript(profile: IMihomoConfig, script: string): IMihomoConfi
5960
return profile
6061
}
6162
}
63+
64+
export async function getRuntimeConfigStr(): Promise<string> {
65+
return await readFile(mihomoWorkConfigPath(), 'utf8')
66+
}
67+
68+
export async function getRuntimeConfig(): Promise<IMihomoConfig> {
69+
return yaml.parse(await getRuntimeConfigStr())
70+
}

src/main/core/manager.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
mihomoWorkConfigPath,
77
mihomoWorkDir
88
} from '../utils/dirs'
9-
import { generateProfile } from '../resolve/factory'
9+
import { generateProfile } from './factory'
1010
import { getAppConfig, patchAppConfig } from '../config'
1111
import { dialog, safeStorage } from 'electron'
1212
import { pauseWebsockets } from './mihomoApi'

src/main/core/mihomoApi.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import axios, { AxiosInstance } from 'axios'
22
import { getAppConfig, getControledMihomoConfig } from '../config'
33
import { mainWindow } from '..'
44
import WebSocket from 'ws'
5-
import { tray } from './tray'
5+
import { tray } from '../resolve/tray'
66
import { calcTraffic } from '../utils/calc'
77

88
let axiosIns: AxiosInstance = null!

src/main/index.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,14 @@ import { electronApp, optimizer, is } from '@electron-toolkit/utils'
22
import { registerIpcMainHandlers } from './utils/ipc'
33
import windowStateKeeper from 'electron-window-state'
44
import { app, shell, BrowserWindow, Menu, dialog, Notification } from 'electron'
5+
import { startMihomoMemory, stopMihomoMemory } from './core/mihomoApi'
6+
import { addProfileItem, getAppConfig } from './config'
57
import { stopCore } from './core/manager'
6-
import { triggerSysProxy } from './resolve/sysproxy'
8+
import { triggerSysProxy } from './sys/sysproxy'
79
import icon from '../../resources/icon.png?asset'
8-
import { createTray } from './core/tray'
9-
import { init } from './resolve/init'
10-
import { addProfileItem, getAppConfig } from './config'
10+
import { createTray } from './resolve/tray'
11+
import { init } from './utils/init'
1112
import { join } from 'path'
12-
import { startMihomoMemory, stopMihomoMemory } from './core/mihomoApi'
1313

1414
export let mainWindow: BrowserWindow | null = null
1515
export let destroyTimer: NodeJS.Timeout | null = null

src/main/core/tray.ts src/main/resolve/tray.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ import {
77
import icoIcon from '../../../resources/icon.ico?asset'
88
import pngIcon from '../../../resources/icon.png?asset'
99
import templateIcon from '../../../resources/iconTemplate.png?asset'
10-
import { patchMihomoConfig } from './mihomoApi'
10+
import { patchMihomoConfig } from '../core/mihomoApi'
1111
import { mainWindow, showMainWindow } from '..'
1212
import { app, ipcMain, Menu, nativeImage, shell, Tray } from 'electron'
1313
import { dataDir, logDir, mihomoCoreDir, mihomoWorkDir } from '../utils/dirs'
14-
import { triggerSysProxy } from '../resolve/sysproxy'
14+
import { triggerSysProxy } from '../sys/sysproxy'
1515

1616
export let tray: Tray | null = null
1717

@@ -105,7 +105,7 @@ const buildContextMenu = async (): Promise<Menu> => {
105105
{
106106
type: 'normal',
107107
label: '应用目录',
108-
click: (): Promise<string> => shell.openPath(dataDir)
108+
click: (): Promise<string> => shell.openPath(dataDir())
109109
},
110110
{
111111
type: 'normal',

src/main/resolve/autoRun.ts src/main/sys/autoRun.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export async function checkAutoRun(): Promise<boolean> {
7676
export async function enableAutoRun(): Promise<void> {
7777
if (process.platform === 'win32') {
7878
const execPromise = promisify(exec)
79-
const taskFilePath = path.join(dataDir, `${appName}.xml`)
79+
const taskFilePath = path.join(dataDir(), `${appName}.xml`)
8080
await writeFile(taskFilePath, taskXml)
8181
await execPromise(`schtasks /create /tn "${appName}" /xml "${taskFilePath}" /f`)
8282
}

src/main/sys/misc.ts

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { exec, execFile } from 'child_process'
2+
import { dialog } from 'electron'
3+
import { readFile } from 'fs/promises'
4+
import path from 'path'
5+
import { promisify } from 'util'
6+
import { exePath, mihomoCorePath, resourcesDir } from '../utils/dirs'
7+
8+
export function getFilePath(ext: string[]): string[] | undefined {
9+
return dialog.showOpenDialogSync({
10+
title: '选择订阅文件',
11+
filters: [{ name: `${ext} file`, extensions: ext }],
12+
properties: ['openFile']
13+
})
14+
}
15+
16+
export async function readTextFile(filePath: string): Promise<string> {
17+
return await readFile(filePath, 'utf8')
18+
}
19+
20+
export async function openUWPTool(): Promise<void> {
21+
const execFilePromise = promisify(execFile)
22+
const uwpToolPath = path.join(resourcesDir(), 'files', 'enableLoopback.exe')
23+
await execFilePromise(uwpToolPath)
24+
}
25+
26+
export async function setupFirewall(): Promise<void> {
27+
const execPromise = promisify(exec)
28+
const removeCommand = `
29+
Remove-NetFirewallRule -DisplayName "mihomo" -ErrorAction SilentlyContinue
30+
Remove-NetFirewallRule -DisplayName "mihomo-alpha" -ErrorAction SilentlyContinue
31+
Remove-NetFirewallRule -DisplayName "Mihomo Party" -ErrorAction SilentlyContinue
32+
`
33+
const createCommand = `
34+
New-NetFirewallRule -DisplayName "mihomo" -Direction Inbound -Action Allow -Program "${mihomoCorePath('mihomo')}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
35+
New-NetFirewallRule -DisplayName "mihomo-alpha" -Direction Inbound -Action Allow -Program "${mihomoCorePath('mihomo-alpha')}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
36+
New-NetFirewallRule -DisplayName "Mihomo Party" -Direction Inbound -Action Allow -Program "${exePath()}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
37+
`
38+
39+
if (process.platform === 'win32') {
40+
await execPromise(removeCommand, { shell: 'powershell' })
41+
await execPromise(createCommand, { shell: 'powershell' })
42+
}
43+
}

src/main/resolve/sysproxy.ts src/main/sys/sysproxy.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { triggerAutoProxy, triggerManualProxy } from '@mihomo-party/sysproxy'
22
import { getAppConfig, getControledMihomoConfig } from '../config'
3-
import { pacPort } from './server'
3+
import { pacPort } from '../resolve/server'
44

55
let defaultBypass: string[]
66

src/main/utils/dirs.ts

+37-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,37 @@
11
import { is } from '@electron-toolkit/utils'
22
import { app } from 'electron'
3+
import fs from 'fs'
4+
import { rm, writeFile } from 'fs/promises'
35
import path from 'path'
46

5-
export const dataDir = app.getPath('userData')
67
export const homeDir = app.getPath('home')
78

9+
export function isPortable(): boolean {
10+
return fs.existsSync(path.join(exeDir(), 'PORTABLE'))
11+
}
12+
13+
export async function setPortable(portable: boolean): Promise<void> {
14+
if (portable) {
15+
await writeFile(path.join(exeDir(), 'PORTABLE'), '')
16+
} else {
17+
await rm(path.join(exeDir(), 'PORTABLE'))
18+
}
19+
app.relaunch()
20+
app.quit()
21+
}
22+
23+
export function dataDir(): string {
24+
if (isPortable()) {
25+
return path.join(exeDir(), 'data')
26+
} else {
27+
return app.getPath('userData')
28+
}
29+
}
30+
31+
export function exeDir(): string {
32+
return path.dirname(exePath())
33+
}
34+
835
export function exePath(): string {
936
return app.getPath('exe')
1037
}
@@ -35,51 +62,51 @@ export function mihomoCorePath(core: string): string {
3562
}
3663

3764
export function appConfigPath(): string {
38-
return path.join(dataDir, 'config.yaml')
65+
return path.join(dataDir(), 'config.yaml')
3966
}
4067

4168
export function controledMihomoConfigPath(): string {
42-
return path.join(dataDir, 'mihomo.yaml')
69+
return path.join(dataDir(), 'mihomo.yaml')
4370
}
4471

4572
export function profileConfigPath(): string {
46-
return path.join(dataDir, 'profile.yaml')
73+
return path.join(dataDir(), 'profile.yaml')
4774
}
4875

4976
export function profilesDir(): string {
50-
return path.join(dataDir, 'profiles')
77+
return path.join(dataDir(), 'profiles')
5178
}
5279

5380
export function profilePath(id: string): string {
5481
return path.join(profilesDir(), `${id}.yaml`)
5582
}
5683

5784
export function overrideDir(): string {
58-
return path.join(dataDir, 'override')
85+
return path.join(dataDir(), 'override')
5986
}
6087

6188
export function overrideConfigPath(): string {
62-
return path.join(dataDir, 'override.yaml')
89+
return path.join(dataDir(), 'override.yaml')
6390
}
6491

6592
export function overridePath(id: string): string {
6693
return path.join(overrideDir(), `${id}.js`)
6794
}
6895

6996
export function mihomoWorkDir(): string {
70-
return path.join(dataDir, 'work')
97+
return path.join(dataDir(), 'work')
7198
}
7299

73100
export function mihomoTestDir(): string {
74-
return path.join(dataDir, 'test')
101+
return path.join(dataDir(), 'test')
75102
}
76103

77104
export function mihomoWorkConfigPath(): string {
78105
return path.join(mihomoWorkDir(), 'config.yaml')
79106
}
80107

81108
export function logDir(): string {
82-
return path.join(dataDir, 'logs')
109+
return path.join(dataDir(), 'logs')
83110
}
84111

85112
export function logPath(): string {

src/main/resolve/init.ts src/main/utils/init.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -11,29 +11,29 @@ import {
1111
profilePath,
1212
profilesDir,
1313
resourcesFilesDir
14-
} from '../utils/dirs'
14+
} from './dirs'
1515
import {
1616
defaultConfig,
1717
defaultControledMihomoConfig,
1818
defaultOverrideConfig,
1919
defaultProfile,
2020
defaultProfileConfig
21-
} from '../utils/template'
21+
} from './template'
2222
import yaml from 'yaml'
2323
import { mkdir, writeFile, copyFile } from 'fs/promises'
2424
import { existsSync } from 'fs'
2525
import path from 'path'
26-
import { startPacServer } from './server'
27-
import { triggerSysProxy } from './sysproxy'
26+
import { startPacServer } from '../resolve/server'
27+
import { triggerSysProxy } from '../sys/sysproxy'
2828
import { getAppConfig } from '../config'
2929
import { app } from 'electron'
3030
import { startCore } from '../core/manager'
3131
import { initProfileUpdater } from '../core/profileUpdater'
3232
import { startMihomoTraffic } from '../core/mihomoApi'
3333

3434
async function initDirs(): Promise<void> {
35-
if (!existsSync(dataDir)) {
36-
await mkdir(dataDir)
35+
if (!existsSync(dataDir())) {
36+
await mkdir(dataDir())
3737
}
3838
if (!existsSync(profilesDir())) {
3939
await mkdir(profilesDir())

src/main/utils/ipc.ts

+8-54
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { app, dialog, ipcMain, safeStorage } from 'electron'
1+
import { app, ipcMain, safeStorage } from 'electron'
22
import {
33
mihomoChangeProxy,
44
mihomoCloseAllConnections,
@@ -19,7 +19,7 @@ import {
1919
stopMihomoConnections,
2020
stopMihomoLogs
2121
} from '../core/mihomoApi'
22-
import { checkAutoRun, disableAutoRun, enableAutoRun } from '../resolve/autoRun'
22+
import { checkAutoRun, disableAutoRun, enableAutoRun } from '../sys/autoRun'
2323
import {
2424
getAppConfig,
2525
patchAppConfig,
@@ -45,14 +45,11 @@ import {
4545
updateOverrideItem
4646
} from '../config'
4747
import { isEncryptionAvailable, manualGrantCorePermition, restartCore } from '../core/manager'
48-
import { triggerSysProxy } from '../resolve/sysproxy'
48+
import { triggerSysProxy } from '../sys/sysproxy'
4949
import { checkUpdate } from '../resolve/autoUpdater'
50-
import { exePath, mihomoCorePath, mihomoWorkConfigPath, resourcesDir } from './dirs'
51-
import { exec, execFile } from 'child_process'
52-
import yaml from 'yaml'
53-
import path from 'path'
54-
import { promisify } from 'util'
55-
import { readFile } from 'fs/promises'
50+
import { getFilePath, openUWPTool, readTextFile, setupFirewall } from '../sys/misc'
51+
import { getRuntimeConfig, getRuntimeConfigStr } from '../core/factory'
52+
import { isPortable, setPortable } from './dirs'
5653

5754
function ipcErrorWrapper<T>( // eslint-disable-next-line @typescript-eslint/no-explicit-any
5855
fn: (...args: any[]) => Promise<T> // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -138,50 +135,7 @@ export function registerIpcMainHandlers(): void {
138135
ipcMain.handle('platform', () => process.platform)
139136
ipcMain.handle('openUWPTool', ipcErrorWrapper(openUWPTool))
140137
ipcMain.handle('setupFirewall', ipcErrorWrapper(setupFirewall))
138+
ipcMain.handle('setPortable', (_e, portable) => ipcErrorWrapper(setPortable)(portable))
139+
ipcMain.handle('isPortable', isPortable)
141140
ipcMain.handle('quitApp', () => app.quit())
142141
}
143-
144-
function getFilePath(ext: string[]): string[] | undefined {
145-
return dialog.showOpenDialogSync({
146-
title: '选择订阅文件',
147-
filters: [{ name: `${ext} file`, extensions: ext }],
148-
properties: ['openFile']
149-
})
150-
}
151-
152-
async function readTextFile(filePath: string): Promise<string> {
153-
return await readFile(filePath, 'utf8')
154-
}
155-
156-
async function getRuntimeConfigStr(): Promise<string> {
157-
return readFile(mihomoWorkConfigPath(), 'utf8')
158-
}
159-
160-
async function getRuntimeConfig(): Promise<IMihomoConfig> {
161-
return yaml.parse(await getRuntimeConfigStr())
162-
}
163-
164-
async function openUWPTool(): Promise<void> {
165-
const execFilePromise = promisify(execFile)
166-
const uwpToolPath = path.join(resourcesDir(), 'files', 'enableLoopback.exe')
167-
await execFilePromise(uwpToolPath)
168-
}
169-
170-
async function setupFirewall(): Promise<void> {
171-
const execPromise = promisify(exec)
172-
const removeCommand = `
173-
Remove-NetFirewallRule -DisplayName "mihomo" -ErrorAction SilentlyContinue
174-
Remove-NetFirewallRule -DisplayName "mihomo-alpha" -ErrorAction SilentlyContinue
175-
Remove-NetFirewallRule -DisplayName "Mihomo Party" -ErrorAction SilentlyContinue
176-
`
177-
const createCommand = `
178-
New-NetFirewallRule -DisplayName "mihomo" -Direction Inbound -Action Allow -Program "${mihomoCorePath('mihomo')}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
179-
New-NetFirewallRule -DisplayName "mihomo-alpha" -Direction Inbound -Action Allow -Program "${mihomoCorePath('mihomo-alpha')}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
180-
New-NetFirewallRule -DisplayName "Mihomo Party" -Direction Inbound -Action Allow -Program "${exePath()}" -Enabled True -Profile Any -ErrorAction SilentlyContinue
181-
`
182-
183-
if (process.platform === 'win32') {
184-
await execPromise(removeCommand, { shell: 'powershell' })
185-
await execPromise(createCommand, { shell: 'powershell' })
186-
}
187-
}

0 commit comments

Comments
 (0)