From 282ae6e6b18feba0221023538424d63b77f7fad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=B6=E7=91=BE?= Date: Fri, 16 Aug 2024 22:09:37 +0800 Subject: [PATCH] fix: close #73 #120 --- src/adapter/input/index.ts | 2 +- src/adapter/onebot/11/event.ts | 8 +- src/adapter/onebot/11/index.ts | 6 +- src/core/index.ts | 2 +- src/core/karin/karin.ts | 48 ++++++++---- src/core/listener/listener.ts | 131 ++++++++++++++++++++++++--------- src/core/plugin/loader.ts | 8 +- src/core/process/process.ts | 8 +- src/core/server/server.ts | 8 +- src/event/handler/message.ts | 10 +-- src/event/handler/notice.ts | 5 +- src/event/handler/request.ts | 3 +- src/utils/common/common.ts | 21 ++++++ src/utils/config/config.ts | 2 +- 14 files changed, 182 insertions(+), 80 deletions(-) diff --git a/src/adapter/input/index.ts b/src/adapter/input/index.ts index f153026..e8a951a 100644 --- a/src/adapter/input/index.ts +++ b/src/adapter/input/index.ts @@ -107,7 +107,7 @@ export class AdapterInput implements KarinAdapter { return { message_id: e.message_id, message_time: Date.now(), raw_data: elements } } - listener.emit('message', e) + listener.emit('adapter.message', e) } async #MsgToFile (type: 'image' | 'record', file: Buffer | string): Promise { diff --git a/src/adapter/onebot/11/event.ts b/src/adapter/onebot/11/event.ts index 13d20d8..bbabca4 100644 --- a/src/adapter/onebot/11/event.ts +++ b/src/adapter/onebot/11/event.ts @@ -87,7 +87,7 @@ export class OB11Event { */ e.replyCallback = async elements => await this.adapter.SendMessage(e.contact, elements) - listener.emit('message', e) + listener.emit('adapter.message', e) } /** @@ -381,7 +381,7 @@ export class OB11Event { */ notice.replyCallback = async elements => await this.adapter.SendMessage(notice.contact, elements) - listener.emit('notice', notice) + listener.emit('adapter.notice', notice) } /** 请求事件 */ @@ -419,7 +419,7 @@ export class OB11Event { */ request.replyCallback = async elements => await this.adapter.SendMessage(request.contact, elements) - listener.emit('request', request) + listener.emit('adapter.request', request) return } case 'group': { @@ -457,7 +457,7 @@ export class OB11Event { */ request.replyCallback = async elements => await this.adapter.SendMessage(request.contact, elements) - listener.emit('request', request) + listener.emit('adapter.request', request) return } default: { diff --git a/src/adapter/onebot/11/index.ts b/src/adapter/onebot/11/index.ts index 0814bdf..9a298bf 100644 --- a/src/adapter/onebot/11/index.ts +++ b/src/adapter/onebot/11/index.ts @@ -1,7 +1,7 @@ import WebSocket from 'ws' import { randomUUID } from 'crypto' import { IncomingMessage } from 'http' -import { listener } from 'karin/core/listener/listener' +import { karin } from 'karin/core/karin/karin' import { common, config, logger, segment } from 'karin/utils' import { GroupHonorInfo, KarinAdapter, LoggerLevel, MessageType, OB11Api, OB11ApiParams, OB11ApiResponse, OB11Segment, OB11SegmentType, Role } from 'karin/types' @@ -104,7 +104,7 @@ export class AdapterOneBot11 implements KarinAdapter { this.socket.removeAllListeners() /** 注销bot */ - this.adapter.index && listener.delBot(this.adapter.index) + this.adapter.index && karin.delBot(this.adapter.index) /** 正向ws需要重连 */ if (this.adapter.sub_type === 'client') { @@ -149,7 +149,7 @@ export class AdapterOneBot11 implements KarinAdapter { this.account.name = data.account_name this.logger('info', `[加载完成][app_name:${this.version.name}][version:${this.version.version}] ` + logger.green(this.adapter.connect as string)) /** 注册bot */ - const index = listener.addBot({ type: this.adapter.type, bot: this }) + const index = karin.addBot({ type: this.adapter.type, bot: this }) if (index) this.adapter.index = index } diff --git a/src/core/index.ts b/src/core/index.ts index a7ed322..1f695ce 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -1,6 +1,6 @@ +export * from './karin/karin' export * from './init/dir' export * from './init/init' -export * from './karin/karin' export * from './listener/listener' export * from './plugin/base' export * from '../types/plugin/app' diff --git a/src/core/karin/karin.ts b/src/core/karin/karin.ts index d8d7b89..9139136 100644 --- a/src/core/karin/karin.ts +++ b/src/core/karin/karin.ts @@ -1,9 +1,8 @@ -import { server } from '../server/server' import { stateArr } from '../plugin/base' -import { common } from 'karin/utils' -import { listener } from '../listener/listener' import onebot11 from 'karin/adapter/onebot/11' -import { render, RenderServer } from 'karin/render' +import { render } from 'karin/render/app' +import { RenderServer } from 'karin/render/server' + import { Scene, Contact, @@ -25,6 +24,11 @@ import { AllRequestSubType, } from 'karin/types' +import { pluginLoader } from '../plugin/loader' +import { common } from 'karin/utils/common/common' +import { logger } from 'karin/utils/core/logger' +import { Listeners } from '../listener/listener' + type FncFunction = (e: KarinMessage) => Promise type FncElement = string | KarinElement | Array type UseReceive = (e: KarinMessageType, next: Function, exit: Function) => Promise @@ -102,10 +106,13 @@ export interface OptionsElement extends OptionsCommand { stop?: boolean } -export class Karin { - start: boolean +export class Karin extends Listeners { + /** 是否启动 */ + #start: boolean constructor () { - this.start = false + super() + + this.#start = false this.run() } @@ -294,7 +301,7 @@ export class Karin { const userId = options?.userId || e.user_id const key = e.group_id ? `${e.group_id}.${userId}` : userId stateArr[key] = { type: 'ctx' } - // 返回promise 设置超时时间 + return new Promise((resolve, reject) => { setTimeout(() => { if (stateArr[key]) { @@ -305,7 +312,7 @@ export class Karin { } }, time * 1000) - listener.once(`ctx:${key}`, (e: KarinMessage) => resolve(e)) + this.once(`ctx:${key}`, (e: KarinMessage) => resolve(e)) }) } @@ -354,15 +361,26 @@ export class Karin { /** * - 启动 */ - run () { - if (this.start) return - this.start = true + async run () { + if (this.#start) return + this.#start = true + const { server } = await import('../server/server') server.init() - listener.emit('load.plugin') - listener.emit('adapter', RenderServer) - listener.emit('adapter', onebot11) + pluginLoader.load() + this.emit('adapter', RenderServer) + this.emit('adapter', onebot11) } } export const karin = new Karin() +/** + * 即将废弃 请使用karin + * @deprecated + */ +export const listener = karin +/** + * 即将废弃 请使用karin + * @deprecated + */ +export const Bot = karin export default karin diff --git a/src/core/listener/listener.ts b/src/core/listener/listener.ts index 565c8ea..1fe3b27 100644 --- a/src/core/listener/listener.ts +++ b/src/core/listener/listener.ts @@ -2,52 +2,111 @@ import { level } from 'karin/db' import { EventEmitter } from 'events' import { pluginLoader } from '../plugin/loader' import { common, logger, config, segment } from 'karin/utils' -import { KarinAdapter, Contact, KarinElement } from 'karin/types' import { MessageHandler, NoticeHandler, RequestHandler } from 'karin/event' +import { + Contact, + KarinElement, + KarinAdapter, + KarinMessage, + KarinNoticeType, + KarinRequestType, + KarinMessageType, +} from 'karin/types' + +type AdapterType = KarinAdapter['adapter']['type'] +type onAdapter = { type: AdapterType; adapter: new () => KarinAdapter; path?: string } /** - * 监听器管理 + * 产生事件映射 */ -export class Listeners extends EventEmitter { - /** - * Bot索引 - * @type - Bot索引 - */ - index: number +export interface EmittEventMap { + 'karin:count:send': number + 'karin:count:fnc': string + error: any + adapter: onAdapter + 'adapter.message': KarinMessageType + 'adapter.notice': KarinNoticeType + 'adapter.request': KarinRequestType + message: KarinMessageType + notice: KarinNoticeType + request: KarinRequestType + 'plugin.watch': undefined + 'restart.grpc': undefined + 'restart.http': undefined +} - /** - * 框架名称 - */ +/** 上下文 */ +type ContextEvents = { + [K in `ctx:${string}`]: (e: KarinMessage) => void +} + +/** + * 监听事件映射 + */ +export interface OnEventMap extends ContextEvents { + 'karin:count:send': (count: number) => void + 'karin:count:fnc': (fnc: string) => void + error: (error: any) => void + adapter: (data: onAdapter) => void + 'adapter.message': (data: KarinMessageType) => void + 'adapter.notice': (data: KarinNoticeType) => void + 'adapter.request': (data: KarinRequestType) => void + message: (data: KarinMessageType) => void + notice: (data: KarinNoticeType) => void + request: (data: KarinRequestType) => void + 'plugin.watch': undefined + 'restart.grpc': undefined + 'restart.http': undefined +} + +/** + * 监听器实例 + */ +export class Listeners extends EventEmitter { + /** 框架名称 */ name: string - list: Array<{ index: number; type: KarinAdapter['adapter']['type']; bot: KarinAdapter }> - adapter: Array<{ type: KarinAdapter['adapter']['type']; adapter: new () => KarinAdapter; path: string }> + /** Bot列表 */ + list: Array<{ index: number; type: AdapterType; bot: KarinAdapter }> + /** 适配器列表 */ + adapter: Array<{ type: AdapterType; adapter: new () => KarinAdapter; path: string }> + /** Bot自增索引 */ + #index: number + /** 是否启动 */ + #start: boolean + constructor () { super() - this.index = 0 + this.#index = 0 this.name = 'Karin' this.list = [] this.adapter = [] this.on('error', data => logger.error(data)) - this.on('load.plugin', () => pluginLoader.load()) - this.on('adapter', data => { - let path = data.path || '无' - if (path && data.type !== 'grpc') path = `ws://127.0.0.1:${config.Server.http.port}${data.path}` - path = logger.green(path) - logger.info(`[适配器][注册][${data.type}]: ` + path) - this.addAdapter(data) - }) - - this.on('message', data => new MessageHandler(data)) - this.on('notice', data => new NoticeHandler(data)) - this.on('request', data => new RequestHandler(data)) + this.on('adapter', data => this.addAdapter(data)) + this.on('adapter.message', data => new MessageHandler(data)) + this.on('adapter.notice', data => new NoticeHandler(data)) + this.on('adapter.request', data => new RequestHandler(data)) + + this.#start = false + } + + on (event: K, listener: OnEventMap[K]): this + on (event: string, listener: (...args: any[]) => void): this + on (event: string | symbol, listener: (...args: any[]) => void): this { + return super.on(event, listener) + } + + emit (event: K, ...args: Parameters): boolean + emit (event: string | symbol, ...args: any[]): boolean + emit (event: string | symbol, ...args: any[]): boolean { + return super.emit(event, ...args) } /** * 注册Bot 返回索引id */ - addBot (data: { bot: KarinAdapter; type: KarinAdapter['adapter']['type'] }): number | false { - this.index++ - const index = this.index + addBot (data: { bot: KarinAdapter; type: AdapterType }): number | false { + this.#index++ + const index = this.#index if (!data.bot) { logger.error('[Bot管理][注册] 注册失败: Bot实例不能为空', JSON.stringify(data)) return false @@ -61,8 +120,8 @@ export class Listeners extends EventEmitter { } /** - * 发送上线通知 - */ + * 发送上线通知 + */ async #online (uid: string) { /** 重启 */ const key = `karin:restart:${uid}` @@ -151,7 +210,12 @@ export class Listeners extends EventEmitter { * @param data.adapter - 适配器实例 * @param data.path - 适配器路径 */ - addAdapter (data: { type: KarinAdapter['adapter']['type']; adapter: new () => KarinAdapter; path?: string }) { + addAdapter (data: onAdapter) { + let path = data.path || '无' + if (path && data.type !== 'grpc') path = `ws://127.0.0.1:${config.Server.http.port}${data.path}` + path = logger.green(path) + logger.info(`[适配器][注册][${data.type}]: ` + path) + const adapter = { type: data.type, adapter: data.adapter, path: '' } if (data.path) adapter.path = data.path this.adapter.push(adapter) @@ -249,6 +313,3 @@ export class Listeners extends EventEmitter { return result } } - -export const listener = new Listeners() -export const Bot = listener diff --git a/src/core/plugin/loader.ts b/src/core/plugin/loader.ts index 9cc3aa4..99b8de8 100644 --- a/src/core/plugin/loader.ts +++ b/src/core/plugin/loader.ts @@ -3,8 +3,8 @@ import path from 'path' import lodash from 'lodash' import chokidar from 'chokidar' import schedule from 'node-schedule' -import { listener } from '../listener/listener' import { render } from 'karin/render' +import { karin } from '../karin/karin' import { common, logger } from 'karin/utils' import { UseInfo, @@ -115,7 +115,7 @@ class PluginLoader { * 插件初始化 */ async load () { - listener.once('plugin.watch', () => { + karin.once('plugin.watch', () => { this.watchList.forEach(async ({ plugin, path }) => { await this.watchDir(plugin, path) logger.debug(`[热更新][${plugin}][${path}] 监听中...`) @@ -136,7 +136,7 @@ class PluginLoader { /** 优先级排序并打印插件信息 */ this.orderBy(true) - listener.emit('plugin.watch') + karin.emit('plugin.watch') return this } @@ -371,7 +371,7 @@ class PluginLoader { if (!isPrint) return - logger.info(`[插件][${Object.keys(this.plugin).length}个] 加载完成`) + logger.info(`[插件][${this.plugin.size}个] 加载完成`) logger.info(`[渲染器][${render.Apps.length}个] 加载完成`) logger.info(`[command][${this.command.length}个] 加载完成`) logger.info(`[button][${this.button.length}个] 加载完成`) diff --git a/src/core/process/process.ts b/src/core/process/process.ts index 52e3db5..32cf720 100644 --- a/src/core/process/process.ts +++ b/src/core/process/process.ts @@ -1,4 +1,4 @@ -import { listener } from '../listener/listener' +import { karin } from '../karin/karin' import { logger, common, config } from 'karin/utils' /** @@ -36,15 +36,15 @@ export default class Process { /** * 捕获警告 */ - process.on('warning', warning => listener.emit('warn', warning)) + process.on('warning', warning => karin.emit('warn', warning)) /** * 捕获错误 */ - process.on('uncaughtException', error => listener.emit('error', error)) + process.on('uncaughtException', error => karin.emit('error', error)) /** * 捕获未处理的Promise错误 */ - process.on('unhandledRejection', error => listener.emit('error', error)) + process.on('unhandledRejection', error => karin.emit('error', error)) return this } diff --git a/src/core/server/server.ts b/src/core/server/server.ts index 2792e74..bf803c4 100644 --- a/src/core/server/server.ts +++ b/src/core/server/server.ts @@ -2,7 +2,7 @@ import fs from 'fs' import Process from '../process/process' import { WebSocketServer } from 'ws' import { createServer } from 'http' -import { listener } from '../listener/listener' +import { karin } from '../karin/karin' import express, { Express } from 'express' import { exec, config, logger, common } from 'karin/utils' import { AdapterOneBot11 } from 'karin/adapter/onebot/11/index' @@ -38,7 +38,7 @@ export const server = new (class Server { const headers = request.headers logger.debug('[反向WS]', path, JSON.stringify(headers, null, 2)) try { - const Adapter = listener.getAdapter(path) + const Adapter = karin.getAdapter(path) if (!Adapter) { logger.error(`[反向WS] 适配器不存在:${path}`) return socket.close() @@ -78,7 +78,7 @@ export const server = new (class Server { if (req.hostname === 'localhost' || req.hostname === '127.0.0.1') { logger.mark('[服务器][HTTP] 收到退出请求,即将退出') /** 关闭服务器 */ - listener.emit('exit.grpc') + karin.emit('exit.grpc') this.server.close() /** 如果是pm2 获取当前pm2ID 使用 */ if (process.env.pm_id) await exec(`pm2 delete ${process.env.pm_id}`) @@ -120,7 +120,7 @@ export const server = new (class Server { logger.mark('[服务器][启动成功][HTTP]: ' + logger.green(`http://${host}:${port}`)) }) - listener.once('restart.http', () => { + karin.once('restart.http', () => { logger.mark('[服务器][重启][HTTP] 正在重启HTTP服务器...') this.#restartServer() }) diff --git a/src/event/handler/message.ts b/src/event/handler/message.ts index 63f4167..ea80b7c 100644 --- a/src/event/handler/message.ts +++ b/src/event/handler/message.ts @@ -2,7 +2,7 @@ import lodash from 'lodash' import { review } from './review' import { EventBaseHandler } from './base' import { logger, config } from 'karin/utils' -import { listener, stateArr, pluginLoader } from 'karin/core' +import { karin, stateArr, pluginLoader } from 'karin/core' import { KarinMessageType, PluginCommandInfoType } from 'karin/types' /** @@ -14,7 +14,6 @@ export class MessageHandler extends EventBaseHandler { super(e) this.e = e this.init() - // todo: emit event if (this.e.group_id) { if (!this.getCd()) return @@ -33,7 +32,7 @@ export class MessageHandler extends EventBaseHandler { * 先对消息事件进行初始化 */ init () { - listener.emit('karin:count:recv', 1) + karin.emit('karin:count:recv', 1) const logs = [] for (const val of this.e.elements) { switch (val.type) { @@ -173,6 +172,7 @@ export class MessageHandler extends EventBaseHandler { logs.length = 0 this.reply() + karin.emit('message', this.e) } /** @@ -246,7 +246,7 @@ export class MessageHandler extends EventBaseHandler { /** 计算插件处理时间 */ const start = Date.now() - listener.emit('karin:count:fnc', this.e.logFnc) + karin.emit('karin:count:fnc', this.e.logFnc) try { let res @@ -280,7 +280,7 @@ export class MessageHandler extends EventBaseHandler { if (App) { switch (App.type) { case 'ctx': { - listener.emit(`ctx:${key}`, this.e) + karin.emit(`ctx:${key}`, this.e) delete stateArr[key] return true } diff --git a/src/event/handler/notice.ts b/src/event/handler/notice.ts index 8ebd0c4..764fcf3 100644 --- a/src/event/handler/notice.ts +++ b/src/event/handler/notice.ts @@ -1,7 +1,7 @@ import { review } from './review' import { EventBaseHandler } from './base' -import { pluginLoader } from 'karin/core' import { logger, config } from 'karin/utils' +import { karin, pluginLoader } from 'karin/core' import { KarinNoticeType, NoticeSubType } from 'karin/types' /** @@ -55,6 +55,7 @@ export class NoticeHandler extends EventBaseHandler { } this.reply() + karin.emit('notice', this.e) } /** @@ -132,7 +133,7 @@ export class NoticeHandler extends EventBaseHandler { /** 群成员增加 */ case NoticeSubType.GroupMemberIncrease: { const { operator_uid, operator_uin, target_uid, target_uin, type } = this.e.content - this.e.raw_message = `[群成员新增]: ${operator_uid || operator_uin} ${type === 'invite' ? '邀请' : '同意'} ${target_uid || target_uin} 加入群聊` + this.e.raw_message = `[群成员新增]: ${operator_uid || operator_uin} ${type === 'invite' ? '邀请' : '同意'} ${target_uid || target_uin} 加入群聊` break } /** 群成员减少 */ diff --git a/src/event/handler/request.ts b/src/event/handler/request.ts index a5dcab2..7da88ab 100644 --- a/src/event/handler/request.ts +++ b/src/event/handler/request.ts @@ -1,6 +1,6 @@ import { review } from './review' import { EventBaseHandler } from './base' -import { pluginLoader } from 'karin/core' +import { karin, pluginLoader } from 'karin/core' import { logger, config } from 'karin/utils' import { KarinRequestType, RequestSubType } from 'karin/types' @@ -51,6 +51,7 @@ export class RequestHandler extends EventBaseHandler { } this.reply() + karin.emit('request', this.e) } /** diff --git a/src/utils/common/common.ts b/src/utils/common/common.ts index 46ccdfb..85baad6 100644 --- a/src/utils/common/common.ts +++ b/src/utils/common/common.ts @@ -204,6 +204,27 @@ class Common { } } + /** + * 传入插件名称 返回解析后的package.json的内容 + * @param name - 插件名称 + */ + pkgJson (name: string): { + name: string, + version: string, + [key: string]: any + } | null { + try { + /** 先查git插件 */ + const gitPath = `./plugins/${name}` + if (fs.existsSync(gitPath)) return this.readJson(`${gitPath}/package.json`) + /** 查npm插件 */ + const require = createRequire(import.meta.url) + return require(`${name}/package.json`) + } catch { + return null + } + } + /** * 输入包名 返回包根目录的绝对路径 仅简单查找 * @param name - 包名 diff --git a/src/utils/config/config.ts b/src/utils/config/config.ts index 4b7a64f..3bf7278 100644 --- a/src/utils/config/config.ts +++ b/src/utils/config/config.ts @@ -3,7 +3,7 @@ import Yaml from 'yaml' import path from 'path' import { Logger } from 'log4js' import chokidar from 'chokidar' -import { karinDir } from 'karin/core' +import { karinDir } from 'karin/core/init/dir' import { common } from 'karin/utils/common/common' import { Redis, App, Config, Server, Package, GroupCfg, KarinEventTypes } from 'karin/types'