mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-21 20:29:03 +08:00
@@ -1,150 +0,0 @@
|
||||
import { invoke } from "@tauri-apps/api/core"
|
||||
|
||||
export interface ConfigChangeEvent {
|
||||
key: string
|
||||
value: any
|
||||
timestamp: number
|
||||
}
|
||||
|
||||
export type ConfigChangeListener = (event: ConfigChangeEvent) => void
|
||||
|
||||
export interface ConfigSpec {
|
||||
// 应用设置
|
||||
is_wizard_completed: boolean
|
||||
log_level: "debug" | "info" | "warn" | "error"
|
||||
window_zoom: number
|
||||
search_keyboard_layout: "t9" | "qwerty26"
|
||||
disable_search_keyboard: boolean
|
||||
font_family: string
|
||||
current_theme_id: string
|
||||
themes_custom: any[]
|
||||
dashboards_config: any[]
|
||||
mobile_bottom_nav_items: string[]
|
||||
|
||||
// 自动评分
|
||||
auto_score_enabled: boolean
|
||||
auto_score_rules: any[]
|
||||
auto_score_batches: any[]
|
||||
|
||||
// 数据库
|
||||
pg_connection_string: string
|
||||
pg_connection_status: {
|
||||
connected: boolean
|
||||
type: "sqlite" | "postgresql"
|
||||
error?: string
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigServiceClass {
|
||||
private cache: Map<string, any> = new Map()
|
||||
private listeners: Set<ConfigChangeListener> = new Set()
|
||||
private initialized = false
|
||||
private initPromise: Promise<void> | null = null
|
||||
|
||||
async initialize(): Promise<void> {
|
||||
if (this.initialized) return
|
||||
if (this.initPromise) return this.initPromise
|
||||
|
||||
this.initPromise = (async () => {
|
||||
try {
|
||||
const result = await this.invokeApi("getAllSettings")
|
||||
if (result.success && result.data) {
|
||||
Object.entries(result.data).forEach(([key, value]) => {
|
||||
this.cache.set(key, value)
|
||||
})
|
||||
}
|
||||
this.setupListener()
|
||||
this.initialized = true
|
||||
} catch (error) {
|
||||
console.error("Failed to initialize config service:", error)
|
||||
throw error
|
||||
}
|
||||
})()
|
||||
|
||||
return this.initPromise
|
||||
}
|
||||
|
||||
async get<K extends keyof ConfigSpec>(key: K): Promise<ConfigSpec[K]> {
|
||||
await this.initialize()
|
||||
return this.cache.get(key)
|
||||
}
|
||||
|
||||
async set<K extends keyof ConfigSpec>(key: K, value: ConfigSpec[K]): Promise<void> {
|
||||
await this.initialize()
|
||||
const result = await this.invokeApi("setSetting", [key, value])
|
||||
if (!result.success) {
|
||||
throw new Error(result.message || "Failed to set config")
|
||||
}
|
||||
this.cache.set(key, value)
|
||||
this.notifyListeners({ key, value, timestamp: Date.now() })
|
||||
}
|
||||
|
||||
async patch(partial: Partial<ConfigSpec>): Promise<void> {
|
||||
await this.initialize()
|
||||
for (const [key, value] of Object.entries(partial)) {
|
||||
await this.set(key as keyof ConfigSpec, value)
|
||||
}
|
||||
}
|
||||
|
||||
getAll(): ConfigSpec {
|
||||
const entries = Array.from(this.cache.entries())
|
||||
return Object.fromEntries(entries) as ConfigSpec
|
||||
}
|
||||
|
||||
has(key: string): boolean {
|
||||
return this.cache.has(key)
|
||||
}
|
||||
|
||||
onChange(listener: ConfigChangeListener): () => void {
|
||||
this.listeners.add(listener)
|
||||
return () => this.listeners.delete(listener)
|
||||
}
|
||||
|
||||
private notifyListeners(event: ConfigChangeEvent): void {
|
||||
this.listeners.forEach((listener) => {
|
||||
try {
|
||||
listener(event)
|
||||
} catch (error) {
|
||||
console.error("Config listener error:", error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private setupListener(): void {
|
||||
const api = (window as any).api
|
||||
if (!api?.onSettingChanged) return
|
||||
|
||||
api
|
||||
.onSettingChanged((change: any) => {
|
||||
if (change?.key && change?.value) {
|
||||
this.cache.set(change.key, change.value)
|
||||
this.notifyListeners({
|
||||
key: change.key,
|
||||
value: change.value,
|
||||
timestamp: Date.now(),
|
||||
})
|
||||
}
|
||||
})
|
||||
.catch(() => void 0)
|
||||
}
|
||||
|
||||
private async invokeApi<T = any>(
|
||||
command: string,
|
||||
args?: any[]
|
||||
): Promise<{ success: boolean; data?: T; message?: string }> {
|
||||
const api = (window as any).api
|
||||
if (api?.[command]) {
|
||||
return await api[command](...(args || []))
|
||||
}
|
||||
|
||||
// Fallback to invoke if API not available
|
||||
try {
|
||||
const result = await invoke(command, args ? { args } : {})
|
||||
return { success: true, data: result as T }
|
||||
} catch (error: any) {
|
||||
return { success: false, message: error.message || "Unknown error" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const ConfigService = new ConfigServiceClass()
|
||||
@@ -1,230 +0,0 @@
|
||||
/**
|
||||
* SecScore 日志服务
|
||||
* 支持分级日志、多色打印、文件存储
|
||||
*/
|
||||
|
||||
export type LogLevel = "debug" | "info" | "warn" | "error"
|
||||
|
||||
export interface LogEntry {
|
||||
level: LogLevel
|
||||
message: string
|
||||
timestamp: number
|
||||
meta?: any
|
||||
source?: string
|
||||
}
|
||||
|
||||
export interface LogWriter {
|
||||
write(entry: LogEntry): void
|
||||
}
|
||||
|
||||
/**
|
||||
* 控制台日志写入器
|
||||
* 支持多色打印
|
||||
*/
|
||||
class ConsoleLogWriter implements LogWriter {
|
||||
private colors: Record<LogLevel, string> = {
|
||||
debug: "\x1b[36m", // Cyan
|
||||
info: "\x1b[32m", // Green
|
||||
warn: "\x1b[33m", // Yellow
|
||||
error: "\x1b[31m", // Red
|
||||
}
|
||||
|
||||
private reset = "\x1b[0m"
|
||||
|
||||
write(entry: LogEntry): void {
|
||||
const { level, message, timestamp, meta, source } = entry
|
||||
const color = this.colors[level]
|
||||
const time = new Date(timestamp).toISOString()
|
||||
const prefix = source ? `[${source}]` : "[SecScore]"
|
||||
|
||||
const logMessage = `${color}${time} ${prefix} [${level.toUpperCase()}]${this.reset} ${message}`
|
||||
|
||||
switch (level) {
|
||||
case "debug":
|
||||
console.debug(logMessage, meta || "")
|
||||
break
|
||||
case "info":
|
||||
console.info(logMessage, meta || "")
|
||||
break
|
||||
case "warn":
|
||||
console.warn(logMessage, meta || "")
|
||||
break
|
||||
case "error":
|
||||
console.error(logMessage, meta || "")
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 远程日志写入器
|
||||
* 将日志发送到 Rust 后端
|
||||
*/
|
||||
class RemoteLogWriter implements LogWriter {
|
||||
write(entry: LogEntry): void {
|
||||
const api = (window as any).api
|
||||
if (!api?.writeLog) return
|
||||
|
||||
const payload = {
|
||||
level: entry.level,
|
||||
message: entry.message,
|
||||
meta: entry.meta,
|
||||
}
|
||||
|
||||
Promise.resolve(api.writeLog(payload)).catch(() => void 0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 日志服务类
|
||||
*/
|
||||
class LoggerServiceClass {
|
||||
private writers: LogWriter[] = []
|
||||
private minLevel: LogLevel = "info"
|
||||
private levelPriority: Record<LogLevel, number> = {
|
||||
debug: 0,
|
||||
info: 1,
|
||||
warn: 2,
|
||||
error: 3,
|
||||
}
|
||||
private source: string = "App"
|
||||
private buffer: LogEntry[] = []
|
||||
private bufferSize = 1000
|
||||
|
||||
constructor() {
|
||||
// 默认添加控制台和远程写入器
|
||||
this.addWriter(new ConsoleLogWriter())
|
||||
this.addWriter(new RemoteLogWriter())
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置日志源
|
||||
*/
|
||||
setSource(source: string): void {
|
||||
this.source = source
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加日志写入器
|
||||
*/
|
||||
addWriter(writer: LogWriter): void {
|
||||
this.writers.push(writer)
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置最低日志级别
|
||||
*/
|
||||
setLevel(level: LogLevel): void {
|
||||
this.minLevel = level
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前日志级别
|
||||
*/
|
||||
getLevel(): LogLevel {
|
||||
return this.minLevel
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入日志
|
||||
*/
|
||||
private log(level: LogLevel, message: string, meta?: any): void {
|
||||
if (this.levelPriority[level] < this.levelPriority[this.minLevel]) {
|
||||
return
|
||||
}
|
||||
|
||||
const entry: LogEntry = {
|
||||
level,
|
||||
message,
|
||||
timestamp: Date.now(),
|
||||
meta,
|
||||
source: this.source,
|
||||
}
|
||||
|
||||
// 添加到缓冲区
|
||||
this.buffer.push(entry)
|
||||
if (this.buffer.length > this.bufferSize) {
|
||||
this.buffer.shift()
|
||||
}
|
||||
|
||||
// 写入所有写入器
|
||||
this.writers.forEach((writer) => {
|
||||
try {
|
||||
writer.write(entry)
|
||||
} catch (error) {
|
||||
console.error("Log writer error:", error)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug 日志
|
||||
*/
|
||||
debug(message: string, meta?: any): void {
|
||||
this.log("debug", message, meta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Info 日志
|
||||
*/
|
||||
info(message: string, meta?: any): void {
|
||||
this.log("info", message, meta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Warning 日志
|
||||
*/
|
||||
warn(message: string, meta?: any): void {
|
||||
this.log("warn", message, meta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Error 日志
|
||||
*/
|
||||
error(message: string, meta?: any): void {
|
||||
this.log("error", message, meta)
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建带指定源的日志记录器
|
||||
*/
|
||||
createChild(source: string): LoggerServiceClass {
|
||||
const child = new LoggerServiceClass()
|
||||
child.writers = [...this.writers]
|
||||
child.minLevel = this.minLevel
|
||||
child.source = source
|
||||
return child
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取最近的日志
|
||||
*/
|
||||
getRecentLogs(count: number = 100): LogEntry[] {
|
||||
return this.buffer.slice(-count)
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空日志缓冲
|
||||
*/
|
||||
clear(): void {
|
||||
this.buffer = []
|
||||
}
|
||||
}
|
||||
|
||||
// 导出全局日志服务实例
|
||||
export const LoggerService = new LoggerServiceClass()
|
||||
|
||||
/**
|
||||
* 便捷日志函数
|
||||
*/
|
||||
export const logger = {
|
||||
debug: (message: string, meta?: any) => LoggerService.debug(message, meta),
|
||||
info: (message: string, meta?: any) => LoggerService.info(message, meta),
|
||||
warn: (message: string, meta?: any) => LoggerService.warn(message, meta),
|
||||
error: (message: string, meta?: any) => LoggerService.error(message, meta),
|
||||
createChild: (source: string) => LoggerService.createChild(source),
|
||||
setLevel: (level: LogLevel) => LoggerService.setLevel(level),
|
||||
getLevel: () => LoggerService.getLevel(),
|
||||
getRecentLogs: (count?: number) => LoggerService.getRecentLogs(count),
|
||||
clear: () => LoggerService.clear(),
|
||||
}
|
||||
Reference in New Issue
Block a user