feat(plugin service): add check log support

This commit is contained in:
star
2025-08-20 20:15:08 +08:00
parent c86fd7b1e4
commit 0e6dba8249
5 changed files with 98 additions and 11 deletions

View File

@@ -157,6 +157,15 @@ ipcMain.handle('service-plugin-loadAllPlugins', async (): Promise<any> => {
}
})
ipcMain.handle('service-plugin-getPluginLog', async (_, pluginId): Promise<any> => {
try {
return await pluginService.getPluginLog(pluginId)
} catch (error: any) {
console.error('Error getting plugin log:', error)
return { error: error.message }
}
})
ipcMain.handle('service-plugin-uninstallPlugin', async (_, pluginId): Promise<any> => {
try {
return await pluginService.uninstallPlugin(pluginId)

View File

@@ -7,7 +7,7 @@ import { getAppDirPath } from '../../utils/path'
import CeruMusicPluginHost from './manager/CeruMusicPluginHost'
import convertEventDrivenPlugin from './manager/converter-event-driven'
import Logger from './logger'
import Logger, { getLog } from './logger'
// 导出类型以解决TypeScript错误
@@ -84,7 +84,7 @@ const pluginService = {
// 重新加载插件以确保正确初始化
const ceruPluginManager = new CeruMusicPluginHost()
await ceruPluginManager.loadPlugin(filePath, new Logger('log/' + pluginId))
await ceruPluginManager.loadPlugin(filePath, new Logger(pluginId))
// 将插件添加到已加载插件列表
loadedPlugins[pluginId] = ceruPluginManager
@@ -221,6 +221,10 @@ const pluginService = {
supportedSources: ceruPluginManager.getSupportedSources()
}
})
},
async getPluginLog(pluginId: string) {
return await getLog(pluginId)
}
}

View File

@@ -1,35 +1,103 @@
import path from 'path'
import fs from 'fs'
import fsPromise from 'fs/promises'
import { getAppDirPath } from '../../utils/path'
import { remove_empty_strings } from '../../utils/array'
function getLogPath(pluginId: string): string {
return path.join(getAppDirPath(), 'plugin', 'logs', `${pluginId}.txt`)
}
const fileLock: Record<string, Promise<any> | undefined> = {}
const waitNum: Record<string, number | undefined> = {}
enum WriteMode {
APPEND,
OVERWRITE
}
function selectWriteFunc(mode: WriteMode): (...args: any[]) => Promise<any> {
switch (mode) {
case WriteMode.APPEND:
return async (filePath: string, content: string): Promise<void> => {
await fsPromise.appendFile(filePath, content)
}
case WriteMode.OVERWRITE:
return async (filePath: string, content: string): Promise<void> => {
await fsPromise.writeFile(filePath, content)
}
}
}
async function writeLog(logPath: string, content: string, mode: WriteMode): Promise<void> {
const writeFunc: (filePath: string, content: string) => Promise<void> = selectWriteFunc(mode)
return await add_promise(logPath, writeFunc(logPath, content))
}
async function add_promise<T>(key: string, promise: Promise<T>): Promise<T> {
const promiseDeleteCheck = async (promise: Promise<T>): Promise<T> => {
waitNum[key] = waitNum[key] ? waitNum[key] + 1 : 1
try {
return await promise
} finally {
waitNum[key] -= 1
if (waitNum[key] === 0) {
delete fileLock[key]
}
}
}
if (!fileLock[key]) {
fileLock[key] = promiseDeleteCheck(promise)
} else {
fileLock[key] = promiseDeleteCheck(
(fileLock[key] as Promise<any>).then(async () => {
return await promise
})
)
}
return fileLock[key]
}
class Logger {
private readonly logFilePath: string
constructor(pluginId: string) {
this.logFilePath = path.join(getAppDirPath(), pluginId, 'log.txt')
this.logFilePath = getLogPath(pluginId)
fsPromise.mkdir(path.dirname(this.logFilePath), { recursive: true }).then()
}
log(...args: any[]) {
log(...args: any[]): void {
this.write(`log ${args.join(' ')}`)
}
info(...args: any[]) {
info(...args: any[]): void {
this.write(`info ${args.join(' ')}`)
}
warn(...args: any[]) {
warn(...args: any[]): void {
this.write(`warn ${args.join(' ')}`)
}
error(...args: any[]) {
error(...args: any[]): void {
this.write(`error ${args.join(' ')}`)
}
private write(msg: string) {
fs.appendFileSync(this.logFilePath, `${msg}\n`)
private write(msg: string): void {
writeLog(this.logFilePath, msg, WriteMode.APPEND).then()
}
}
async function getLog(pluginId: string) {
const logFilePath: string = getLogPath(pluginId)
return await add_promise(
logFilePath,
(async (): Promise<string[]> => {
const content: string = await fsPromise.readFile(logFilePath, 'utf-8')
const last200Lines: string[] = remove_empty_strings(content.split('\n')).slice(-200)
await selectWriteFunc(WriteMode.OVERWRITE)(logFilePath, last200Lines.join('\n'))
return last200Lines
})()
)
}
export default Logger
export { Logger, getLog }

5
src/main/utils/array.ts Normal file
View File

@@ -0,0 +1,5 @@
function remove_empty_strings(arr: string[]) {
return arr.filter((item: string): boolean => item !== '')
}
export { remove_empty_strings }

View File

@@ -35,7 +35,8 @@ const api = {
getPluginById: (id: string) => ipcRenderer.invoke('service-plugin-getPluginById', id),
loadAllPlugins: () => ipcRenderer.invoke('service-plugin-loadAllPlugins'),
uninstallPlugin: (pluginId: string) =>
ipcRenderer.invoke('service-plugin-uninstallPlugin', pluginId)
ipcRenderer.invoke('service-plugin-uninstallPlugin', pluginId),
getPluginLog: (pluginId: string) => ipcRenderer.invoke('service-plugin-getPluginLog', pluginId)
},
ai: {