- 将 electron 代码重构为基于服务的模块化架构,提升可维护性 - 将 `electron/games/manager.ts` 移至 `electron/services/game.ts` 并重构为 GameService - 新增多个服务模块:category, database, game-scanner, node, process, proxy-monitor, singbox, system, updater - 新增工具模块:command, format, id, ping, port, process-helper - 新增公共模块:store(基于 JSON 的持久化存储) - 新增文档:singbox-config.md 和 electron-structure.md 说明新架构 - 更新主入口文件 `electron/main/index.ts` 以初始化所有服务 - 更新预加载脚本 `electron/preload/index.ts` 暴露新的 API - 更新构建配置以支持新的目录结构 - 修复主入口文件路径配置
71 lines
1.7 KiB
TypeScript
71 lines
1.7 KiB
TypeScript
/**
|
||
* 检查字符串是否为有效的图标 URL
|
||
*
|
||
* 支持 http/https/file 协议及 data URI scheme。
|
||
*
|
||
* @param value - 要检查的字符串
|
||
* @returns boolean - 如果是有效图标 URL 则返回 true
|
||
*/
|
||
export function isIconUrl(value: string): boolean {
|
||
const v = value.trim()
|
||
return (
|
||
v.startsWith('http://') ||
|
||
v.startsWith('https://') ||
|
||
v.startsWith('file://') ||
|
||
v.startsWith('data:')
|
||
)
|
||
}
|
||
|
||
/**
|
||
* 标准化节点类型字符串
|
||
*
|
||
* 将输入的节点类型转换为统一的内部标识符。
|
||
* 例如:'ss' -> 'shadowsocks'
|
||
*
|
||
* @param type - 原始节点类型
|
||
* @returns string - 标准化后的节点类型
|
||
*/
|
||
export function normalizeNodeType(type: unknown): string {
|
||
const t = String(type ?? '').trim().toLowerCase()
|
||
if (t === 'ss' || t === 'shadowsocks') return 'shadowsocks'
|
||
return t
|
||
}
|
||
|
||
/**
|
||
* 安全解析 JSON 字符串
|
||
*
|
||
* 尝试解析 JSON,如果失败则返回默认值,避免抛出异常。
|
||
*
|
||
* @template T - 返回值的类型
|
||
* @param value - JSON 字符串
|
||
* @param fallback - 解析失败时返回的默认值
|
||
* @returns T - 解析结果或默认值
|
||
*/
|
||
export function safeJsonParse<T>(value: string, fallback: T): T {
|
||
try {
|
||
return JSON.parse(value) as T
|
||
} catch {
|
||
return fallback
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 解析字符串数组
|
||
*
|
||
* 支持解析 JSON 数组字符串或逗号分隔的字符串。
|
||
*
|
||
* @param value - 输入字符串
|
||
* @returns string[] - 解析后的字符串数组
|
||
*/
|
||
export function parseStringArray(value: string): string[] {
|
||
try {
|
||
const parsed = JSON.parse(value)
|
||
if (Array.isArray(parsed)) {
|
||
return parsed.map(v => String(v).trim()).filter(Boolean)
|
||
}
|
||
} catch {
|
||
// ignore
|
||
}
|
||
return value.split(/[,,]/).map(v => v.trim()).filter(Boolean)
|
||
}
|