mirror of
https://github.com/hicccc77/WeFlow.git
synced 2026-04-28 15:09:19 +00:00
fix: support service runtime fallbacks
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
import { join } from 'path'
|
||||
import { app, safeStorage } from 'electron'
|
||||
import { dirname, join } from 'path'
|
||||
import crypto from 'crypto'
|
||||
import Store from 'electron-store'
|
||||
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'
|
||||
import { expandHomePath } from '../utils/pathUtils'
|
||||
import { getElectronSafeStorage, getPathFallback, isWorkerRuntime } from './electronRuntime'
|
||||
|
||||
// 加密前缀标记
|
||||
const SAFE_PREFIX = 'safe:' // safeStorage 加密(普通模式)
|
||||
const isSafeStorageAvailable = (): boolean => {
|
||||
try {
|
||||
const safeStorage = getElectronSafeStorage()
|
||||
return typeof safeStorage?.isEncryptionAvailable === 'function' && safeStorage.isEncryptionAvailable()
|
||||
} catch {
|
||||
return false
|
||||
@@ -112,6 +113,68 @@ interface ConfigSchema {
|
||||
aiInsightDebugLogEnabled: boolean
|
||||
}
|
||||
|
||||
interface ConfigStoreLike<T extends Record<string, any>> {
|
||||
get<K extends keyof T>(key: K): T[K]
|
||||
set<K extends keyof T>(key: K, value: T[K]): void
|
||||
clear(): void
|
||||
store: T
|
||||
}
|
||||
|
||||
function cloneJson<T>(value: T): T {
|
||||
return JSON.parse(JSON.stringify(value))
|
||||
}
|
||||
|
||||
class JsonConfigStore<T extends Record<string, any>> implements ConfigStoreLike<T> {
|
||||
private readonly filePath: string
|
||||
private readonly defaults: T
|
||||
private data: T
|
||||
|
||||
constructor(options: { name: string; defaults: T; cwd?: string }) {
|
||||
const baseDir = options.cwd || getPathFallback('userData')
|
||||
mkdirSync(baseDir, { recursive: true })
|
||||
this.filePath = join(baseDir, `${options.name}.json`)
|
||||
this.defaults = cloneJson(options.defaults)
|
||||
this.data = cloneJson(options.defaults)
|
||||
this.load()
|
||||
}
|
||||
|
||||
get store(): T {
|
||||
return this.data
|
||||
}
|
||||
|
||||
private load(): void {
|
||||
try {
|
||||
if (!existsSync(this.filePath)) return
|
||||
const raw = readFileSync(this.filePath, 'utf8')
|
||||
const parsed = JSON.parse(raw)
|
||||
if (parsed && typeof parsed === 'object') {
|
||||
this.data = { ...cloneJson(this.defaults), ...parsed }
|
||||
}
|
||||
} catch {
|
||||
this.data = cloneJson(this.defaults)
|
||||
}
|
||||
}
|
||||
|
||||
private persist(): void {
|
||||
mkdirSync(dirname(this.filePath), { recursive: true })
|
||||
writeFileSync(this.filePath, JSON.stringify(this.data), 'utf8')
|
||||
}
|
||||
|
||||
get<K extends keyof T>(key: K): T[K] {
|
||||
return this.data[key]
|
||||
}
|
||||
|
||||
set<K extends keyof T>(key: K, value: T[K]): void {
|
||||
this.data[key] = value
|
||||
this.persist()
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
this.data = cloneJson(this.defaults)
|
||||
this.persist()
|
||||
}
|
||||
}
|
||||
|
||||
// 需要 safeStorage 加密的字段(普通模式)
|
||||
const ENCRYPTED_STRING_KEYS: Set<string> = new Set([
|
||||
'decryptKey',
|
||||
@@ -131,7 +194,7 @@ const LOCKABLE_NUMBER_KEYS: Set<string> = new Set(['imageXorKey'])
|
||||
|
||||
export class ConfigService {
|
||||
private static instance: ConfigService
|
||||
private store!: Store<ConfigSchema>
|
||||
private store!: ConfigStoreLike<ConfigSchema>
|
||||
|
||||
// 锁定模式运行时状态
|
||||
private unlockedKeys: Map<string, any> = new Map()
|
||||
@@ -225,36 +288,17 @@ export class ConfigService {
|
||||
aiInsightDebugLogEnabled: false
|
||||
}
|
||||
|
||||
const storeOptions: any = {
|
||||
const cwd = String(process.env.WEFLOW_CONFIG_CWD || process.env.WEFLOW_USER_DATA_PATH || '').trim()
|
||||
this.store = new JsonConfigStore<ConfigSchema>({
|
||||
name: 'WeFlow-config',
|
||||
defaults,
|
||||
projectName: String(process.env.WEFLOW_PROJECT_NAME || 'WeFlow').trim() || 'WeFlow'
|
||||
}
|
||||
const runningInWorker = process.env.WEFLOW_WORKER === '1'
|
||||
if (runningInWorker) {
|
||||
const cwd = String(process.env.WEFLOW_CONFIG_CWD || process.env.WEFLOW_USER_DATA_PATH || '').trim()
|
||||
if (cwd) {
|
||||
storeOptions.cwd = cwd
|
||||
}
|
||||
}
|
||||
cwd: cwd || undefined
|
||||
})
|
||||
|
||||
try {
|
||||
this.store = new Store<ConfigSchema>(storeOptions)
|
||||
} catch (error) {
|
||||
const message = String((error as Error)?.message || error || '')
|
||||
if (message.includes('projectName')) {
|
||||
const fallbackOptions = {
|
||||
...storeOptions,
|
||||
projectName: 'WeFlow',
|
||||
cwd: storeOptions.cwd || process.env.WEFLOW_CONFIG_CWD || process.env.WEFLOW_USER_DATA_PATH || process.cwd()
|
||||
}
|
||||
this.store = new Store<ConfigSchema>(fallbackOptions)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
if (!isWorkerRuntime()) {
|
||||
this.migrateAuthFields()
|
||||
this.migrateAiConfig()
|
||||
}
|
||||
this.migrateAuthFields()
|
||||
this.migrateAiConfig()
|
||||
}
|
||||
|
||||
// === 状态查询 ===
|
||||
@@ -356,6 +400,8 @@ export class ConfigService {
|
||||
if (!plaintext) return ''
|
||||
if (plaintext.startsWith(SAFE_PREFIX)) return plaintext
|
||||
if (!isSafeStorageAvailable()) return plaintext
|
||||
const safeStorage = getElectronSafeStorage()
|
||||
if (!safeStorage) return plaintext
|
||||
const encrypted = safeStorage.encryptString(plaintext)
|
||||
return SAFE_PREFIX + encrypted.toString('base64')
|
||||
}
|
||||
@@ -364,6 +410,8 @@ export class ConfigService {
|
||||
if (!stored) return ''
|
||||
if (!stored.startsWith(SAFE_PREFIX)) return stored
|
||||
if (!isSafeStorageAvailable()) return ''
|
||||
const safeStorage = getElectronSafeStorage()
|
||||
if (!safeStorage) return ''
|
||||
try {
|
||||
const buf = Buffer.from(stored.slice(SAFE_PREFIX.length), 'base64')
|
||||
return safeStorage.decryptString(buf)
|
||||
@@ -831,7 +879,7 @@ export class ConfigService {
|
||||
if (workerUserDataPath) {
|
||||
return workerUserDataPath
|
||||
}
|
||||
return app?.getPath?.('userData') || process.cwd()
|
||||
return getPathFallback('userData')
|
||||
}
|
||||
|
||||
getCacheBasePath(): string {
|
||||
|
||||
Reference in New Issue
Block a user