import { appConfigPath, controledMihomoConfigPath, dataDir, logDir, mihomoTestDir, mihomoWorkDir, overrideConfigPath, overrideDir, profileConfigPath, profilePath, profilesDir, resourcesFilesDir, subStoreDir } from './dirs' import { defaultConfig, defaultControledMihomoConfig, defaultOverrideConfig, defaultProfile, defaultProfileConfig } from './template' import yaml from 'yaml' import { mkdir, writeFile, copyFile, rm, readdir } from 'fs/promises' import { existsSync } from 'fs' import path from 'path' import { startPacServer, startSubStoreServer } from '../resolve/server' import { triggerSysProxy } from '../sys/sysproxy' import { getAppConfig, patchAppConfig } from '../config' import { app } from 'electron' async function initDirs(): Promise { if (!existsSync(dataDir())) { await mkdir(dataDir()) } if (!existsSync(profilesDir())) { await mkdir(profilesDir()) } if (!existsSync(overrideDir())) { await mkdir(overrideDir()) } if (!existsSync(mihomoWorkDir())) { await mkdir(mihomoWorkDir()) } if (!existsSync(logDir())) { await mkdir(logDir()) } if (!existsSync(mihomoTestDir())) { await mkdir(mihomoTestDir()) } if (!existsSync(subStoreDir())) { await mkdir(subStoreDir()) } } async function initConfig(): Promise { if (!existsSync(appConfigPath())) { await writeFile(appConfigPath(), yaml.stringify(defaultConfig)) } if (!existsSync(profileConfigPath())) { await writeFile(profileConfigPath(), yaml.stringify(defaultProfileConfig)) } if (!existsSync(overrideConfigPath())) { await writeFile(overrideConfigPath(), yaml.stringify(defaultOverrideConfig)) } if (!existsSync(profilePath('default'))) { await writeFile(profilePath('default'), yaml.stringify(defaultProfile)) } if (!existsSync(controledMihomoConfigPath())) { await writeFile(controledMihomoConfigPath(), yaml.stringify(defaultControledMihomoConfig)) } } async function initFiles(): Promise { const copy = async (file: string): Promise => { const targetPath = path.join(mihomoWorkDir(), file) const testTargrtPath = path.join(mihomoTestDir(), file) const sourcePath = path.join(resourcesFilesDir(), file) if (!existsSync(targetPath) && existsSync(sourcePath)) { await copyFile(sourcePath, targetPath) } if (!existsSync(testTargrtPath) && existsSync(sourcePath)) { await copyFile(sourcePath, testTargrtPath) } } await Promise.all([ copy('country.mmdb'), copy('geoip.dat'), copy('geosite.dat'), copy('ASN.mmdb') ]) } async function cleanup(): Promise { // update cache const files = await readdir(dataDir()) for (const file of files) { if (file.endsWith('.exe') || file.endsWith('.dmg')) { try { await rm(path.join(dataDir(), file)) } catch { // ignore } } } // logs const { maxLogDays = 7 } = await getAppConfig() const logs = await readdir(logDir()) for (const log of logs) { const date = new Date(log.split('.')[0]) const diff = Date.now() - date.getTime() if (diff > maxLogDays * 24 * 60 * 60 * 1000) { try { await rm(path.join(logDir(), log)) } catch { // ignore } } } } async function migration(): Promise { const { siderOrder = [ 'sysproxy', 'tun', 'profile', 'proxy', 'rule', 'resource', 'override', 'connection', 'mihomo', 'dns', 'sniff', 'log', 'substore' ], useSubStore = true } = await getAppConfig() // add substore sider card if (useSubStore && !siderOrder.includes('substore')) { await patchAppConfig({ siderOrder: [...siderOrder, 'substore'] }) } } function initDeeplink(): void { if (process.defaultApp) { if (process.argv.length >= 2) { app.setAsDefaultProtocolClient('clash', process.execPath, [path.resolve(process.argv[1])]) app.setAsDefaultProtocolClient('mihomo', process.execPath, [path.resolve(process.argv[1])]) } } else { app.setAsDefaultProtocolClient('clash') app.setAsDefaultProtocolClient('mihomo') } } export async function init(): Promise { await initDirs() await initConfig() await migration() await initFiles() await cleanup() await startPacServer() await startSubStoreServer() const { sysProxy } = await getAppConfig() await triggerSysProxy(sysProxy.enable) initDeeplink() }