From 90c4eb86dbefd236b7a672a8c5a0c0a848964fff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=97=B6=E7=91=BE?= <74231782+sj817@users.noreply.github.com> Date: Fri, 17 Jan 2025 05:38:57 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=83=AD=E6=9B=B4=E6=96=B0`.env`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/core/src/adapter/input/index.ts | 32 ++++- .../core/src/event/handler/other/handler.ts | 116 ++++++++++++------ packages/core/src/types/config/config.ts | 52 ++++---- packages/core/src/types/config/privates.ts | 33 ++--- packages/core/src/utils/config/config.ts | 17 +-- packages/core/src/utils/config/env.ts | 21 ++++ packages/core/src/utils/config/index.ts | 1 + 7 files changed, 182 insertions(+), 90 deletions(-) create mode 100644 packages/core/src/utils/config/env.ts diff --git a/packages/core/src/adapter/input/index.ts b/packages/core/src/adapter/input/index.ts index 9592914..a6a9f84 100644 --- a/packages/core/src/adapter/input/index.ts +++ b/packages/core/src/adapter/input/index.ts @@ -24,7 +24,9 @@ const botID = 'console' export class AdapterConsole extends AdapterBase implements AdapterType { constructor () { super() - listeners.on('karin:adapter:open', () => process.stdin.on('data', data => this.createEvent(data))) + listeners.on('karin:adapter:open', () => + process.stdin.on('data', data => this.createEvent(data)), + ) listeners.on('karin:adapter:close', () => process.stdin.removeAllListeners('data')) this.adapter.name = '@karinjs/console' @@ -44,10 +46,25 @@ export class AdapterConsole extends AdapterBase implements AdapterType { return this.account.selfId } - createEvent (data: Buffer) { + async createEvent (data: Buffer) { const text = data.toString().trim() const seq = Math.floor(Math.random() * 1000000000) const time = Date.now() + + /** 如果是日志等级更新命令 */ + if (text.startsWith('log')) { + const level = text.replace(/^log/, '').trim() + if (level) { + const list = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'] + if (list.includes(level)) { + const { updateLevel } = await import('@/utils/config/config') + updateLevel(level) + logger.info(`日志等级已更新为: ${level}`) + return + } + } + } + /** 如果带`group`前缀 则视为群环境 */ if (text.startsWith('group')) { const contact = contactGroup('10010') @@ -61,7 +78,7 @@ export class AdapterConsole extends AdapterBase implements AdapterType { rawEvent: { data }, sender: senderGroup(botID, 'member'), time, - srcReply: (elements) => this.sendMsg(contact, elements), + srcReply: elements => this.sendMsg(contact, elements), }) return } @@ -77,11 +94,15 @@ export class AdapterConsole extends AdapterBase implements AdapterType { rawEvent: { data }, sender: senderFriend(botID, ''), time, - srcReply: (elements) => this.sendMsg(contact, elements), + srcReply: elements => this.sendMsg(contact, elements), }) } - async sendMsg (contact: Contact, elements: Array, retryCount?: number): Promise { + async sendMsg ( + contact: Contact, + elements: Array, + retryCount?: number, + ): Promise { const time = Date.now() const messageId = (++index).toString() const result: SendMsgResults = { @@ -105,7 +126,6 @@ export class AdapterConsole extends AdapterBase implements AdapterType { continue } - // if (['image', 'record', 'video'].includes(v.type)) { if (v.type === 'image' || v.type === 'record' || v.type === 'video') { const url = v.file.startsWith('http') ? v.file : await this.getUrl(v.file, '.png') msg.push(`[${v.type}: ${logger.blue(url)} ]`) diff --git a/packages/core/src/event/handler/other/handler.ts b/packages/core/src/event/handler/other/handler.ts index 1e059fb..806a746 100644 --- a/packages/core/src/event/handler/other/handler.ts +++ b/packages/core/src/event/handler/other/handler.ts @@ -7,21 +7,14 @@ import { config as cfg, getFriendCfg, getGroupCfg } from '@/utils/config' import type { Message, Event } from '@/types/event' import type { AdapterProtocol } from '@/types/adapter' -import type { - GroupMessage, - GroupTempMessage, - GuildMessage, -} from '../../message' +import type { GroupMessage, GroupTempMessage, GuildMessage } from '../../message' /** * @description 日志 * @param userId 用户ID * @param text 日志内容 */ -export const log = ( - userId: string, - text: string -) => logger.debug(`[消息过滤][${userId}] ${text}`) +export const log = (userId: string, text: string) => logger.debug(`[消息过滤][${userId}] ${text}`) /** * @description 初始化`msg` `rawMessage` @@ -38,15 +31,15 @@ export const initMsg = (ctx: Message) => { * @param ctx 事件对象 * @param config 基本配置 */ -export const initRole = ( - ctx: Event, - config: ReturnType -) => { +export const initRole = (ctx: Event, config: ReturnType) => { /** 主人 */ if (config.master.includes(`${ctx.selfId}@${ctx.userId}`) || config.master.includes(ctx.userId)) { ctx.isMaster = true ctx.isAdmin = true - } else if (config.admin.includes(`${ctx.selfId}@${ctx.userId}`) || config.admin.includes(ctx.userId)) { + } else if ( + config.admin.includes(`${ctx.selfId}@${ctx.userId}`) || + config.admin.includes(ctx.userId) + ) { /** 管理员 */ ctx.isAdmin = true ctx.isMaster = false @@ -91,8 +84,8 @@ export const initEmit = (ctx: Event) => { * @returns `true` 表示通过 */ export const disableViaAdapter = ( - plugin: typeof cache.command[number] | typeof cache.accept[number], - protocol: AdapterProtocol + plugin: (typeof cache.command)[number] | (typeof cache.accept)[number], + protocol: AdapterProtocol, ): boolean => { /** 插件指定只允许特定适配器使用 */ if (plugin.adapter.length && !plugin.adapter.includes(protocol)) { @@ -114,8 +107,8 @@ export const disableViaAdapter = ( * @returns `true` 表示通过 */ export const disableViaPluginWhitelist = ( - plugin: typeof cache.command[number] | typeof cache.accept[number], - config: ReturnType | ReturnType + plugin: (typeof cache.command)[number] | (typeof cache.accept)[number], + config: ReturnType | ReturnType, ) => { /** 未设置白名单 */ if (!config.enable.length) return true @@ -148,8 +141,8 @@ export const disableViaPluginWhitelist = ( * @returns `true` 表示通过 */ export const disableViaPluginBlacklist = ( - plugin: typeof cache.command[number] | typeof cache.accept[number], - config: ReturnType | ReturnType + plugin: (typeof cache.command)[number] | (typeof cache.accept)[number], + config: ReturnType | ReturnType, ) => { /** 未设置黑名单 */ if (!config.disable.length) return true @@ -184,8 +177,20 @@ export const privateFilterEvent = ( ctx: Event, config: ReturnType, friend: ReturnType, - cd: boolean + cd: boolean, ): boolean => { + if (ctx.isFriend) { + if (!config?.user?.enable) { + log(ctx.userId, `当前好友事件未启用: ${ctx.eventId}`) + return false + } + } else { + if (!config?.directs?.enable) { + log(ctx.userId, `当前频道私信事件未启用: ${ctx.eventId}`) + return false + } + } + if (!cd) { log(ctx.userId, `当前处于CD中: ${ctx.eventId}`) return false @@ -256,8 +261,20 @@ export const groupFilterEvent = ( ctx: Event, config: ReturnType, group: ReturnType, - cd: boolean + cd: boolean, ): boolean => { + if (ctx.isGroup) { + if (!config?.group?.enable) { + log(ctx.groupId, `当前群事件未启用: ${ctx.eventId}`) + return false + } + } else if (ctx.isGuild) { + if (!config?.guilds?.enable) { + log(ctx.guildId, `当前频道事件未启用: ${ctx.eventId}`) + return false + } + } + if (!cd) { log(ctx.userId, `当前处于CD中: ${ctx.eventId}`) return false @@ -301,7 +318,8 @@ export const groupFilterEvent = ( log(ctx.userId, `用户处于群成员黑名单: ${ctx.eventId}`) return false } - } if (ctx.isGuild) { + } + if (ctx.isGuild) { /** 频道白名单 */ if (config?.guilds?.enable_list?.length && !config?.guilds?.enable_list.includes(ctx.guildId)) { log(ctx.guildId, `频道未处于白名单: ${ctx.eventId}`) @@ -309,17 +327,26 @@ export const groupFilterEvent = ( } /** 频道黑名单 */ - if (config?.guilds?.disable_list?.length && config?.guilds?.disable_list.includes(ctx.guildId)) { + if ( + config?.guilds?.disable_list?.length && + config?.guilds?.disable_list.includes(ctx.guildId) + ) { log(ctx.guildId, `频道处于黑名单: ${ctx.eventId}`) return false } - if (config?.channels?.enable_list?.length && !config?.channels?.enable_list.includes(ctx.channelId)) { + if ( + config?.channels?.enable_list?.length && + !config?.channels?.enable_list.includes(ctx.channelId) + ) { log(ctx.channelId, `子频道未处于白名单: ${ctx.eventId}`) return false } - if (config?.channels?.disable_list?.length && config?.channels?.disable_list.includes(ctx.channelId)) { + if ( + config?.channels?.disable_list?.length && + config?.channels?.disable_list.includes(ctx.channelId) + ) { log(ctx.channelId, `子频道处于黑名单: ${ctx.eventId}`) return false } @@ -399,14 +426,20 @@ export const groupFilterEvent = ( */ export const groupPrint = ( ctx: GroupMessage | GroupTempMessage, - config: ReturnType + config: ReturnType, ): boolean => { - if (config?.group?.log_enable_list?.length && !config?.group?.log_enable_list.includes(ctx.groupId)) { + if ( + config?.group?.log_enable_list?.length && + !config?.group?.log_enable_list.includes(ctx.groupId) + ) { log(ctx.groupId, `群未处于白名单: ${ctx.eventId}`) return false } - if (config?.group?.log_disable_list?.length && config?.group?.log_disable_list.includes(ctx.groupId)) { + if ( + config?.group?.log_disable_list?.length && + config?.group?.log_disable_list.includes(ctx.groupId) + ) { log(ctx.groupId, `群处于黑名单: ${ctx.eventId}`) return false } @@ -420,26 +453,35 @@ export const groupPrint = ( * @param config 基本配置对象 * @returns `true` 表示通过 */ -export const guildPrint = ( - ctx: GuildMessage, - config: ReturnType -): boolean => { - if (config?.guilds?.log_enable_list?.length && !config?.guilds?.log_enable_list.includes(ctx.guildId)) { +export const guildPrint = (ctx: GuildMessage, config: ReturnType): boolean => { + if ( + config?.guilds?.log_enable_list?.length && + !config?.guilds?.log_enable_list.includes(ctx.guildId) + ) { log(ctx.guildId, `频道日志未处于白名单: ${ctx.eventId}`) return false } - if (config?.guilds?.log_disable_list?.length && config?.guilds?.log_disable_list.includes(ctx.guildId)) { + if ( + config?.guilds?.log_disable_list?.length && + config?.guilds?.log_disable_list.includes(ctx.guildId) + ) { log(ctx.guildId, `频道日志处于黑名单: ${ctx.eventId}`) return false } - if (config?.channels?.log_enable_list?.length && !config?.channels?.log_enable_list.includes(ctx.channelId)) { + if ( + config?.channels?.log_enable_list?.length && + !config?.channels?.log_enable_list.includes(ctx.channelId) + ) { log(ctx.channelId, `子频道日志未处于白名单: ${ctx.eventId}`) return false } - if (config?.channels?.log_disable_list?.length && config?.channels?.log_disable_list.includes(ctx.channelId)) { + if ( + config?.channels?.log_disable_list?.length && + config?.channels?.log_disable_list.includes(ctx.channelId) + ) { log(ctx.channelId, `子频道日志处于黑名单: ${ctx.eventId}`) return false } diff --git a/packages/core/src/types/config/config.ts b/packages/core/src/types/config/config.ts index b9e78b8..9224855 100644 --- a/packages/core/src/types/config/config.ts +++ b/packages/core/src/types/config/config.ts @@ -8,73 +8,75 @@ export interface Config { admin: string[] /** 用户管理 */ user: { + /** 是否启用用户事件 */ + enable: boolean /** 用户白名单 */ enable_list: string[] /** 用户黑名单 */ disable_list: string[] - }, + } /** 好友管理 */ friend: { /** 是否启用好友消息事件 */ - enable: boolean, + enable: boolean /** 好友白名单 */ - enable_list: string[], + enable_list: string[] /** 好友黑名单 */ - disable_list: string[], + disable_list: string[] /** 好友日志白名单 */ - log_enable_list: string[], + log_enable_list: string[] /** 好友日志黑名单 */ log_disable_list: string[] - }, + } /** 群管理 */ group: { /** 是否启用群消息事件 */ - enable: boolean, + enable: boolean /** 群白名单 */ - enable_list: string[], + enable_list: string[] /** 群黑名单 */ - disable_list: string[], + disable_list: string[] /** 群日志白名单 */ - log_enable_list: string[], + log_enable_list: string[] /** 群日志黑名单 */ log_disable_list: string[] - }, + } /** 频道私信管理 */ directs: { /** 是否启用私信消息事件 */ - enable: boolean, + enable: boolean /** 私信白名单 */ - enable_list: string[], + enable_list: string[] /** 私信黑名单 */ - disable_list: string[], + disable_list: string[] /** 私信日志白名单 */ - log_enable_list: string[], + log_enable_list: string[] /** 私信日志黑名单 */ log_disable_list: string[] - }, + } /** 频道管理 */ guilds: { /** 是否启用频道消息事件 */ - enable: boolean, + enable: boolean /** 频道白名单 */ - enable_list: string[], + enable_list: string[] /** 频道黑名单 */ - disable_list: string[], + disable_list: string[] /** 频道日志白名单 */ - log_enable_list: string[], + log_enable_list: string[] /** 频道日志黑名单 */ log_disable_list: string[] - }, + } /** 频道消息管理 */ channels: { /** 是否启用频道消息事件 */ - enable: boolean, + enable: boolean /** 频道白名单 */ - enable_list: string[], + enable_list: string[] /** 频道黑名单 */ - disable_list: string[], + disable_list: string[] /** 频道日志白名单 */ - log_enable_list: string[], + log_enable_list: string[] /** 频道日志黑名单 */ log_disable_list: string[] } diff --git a/packages/core/src/types/config/privates.ts b/packages/core/src/types/config/privates.ts index 59b6111..14ec36b 100644 --- a/packages/core/src/types/config/privates.ts +++ b/packages/core/src/types/config/privates.ts @@ -1,17 +1,20 @@ /** - * `private.json` 类型 + * `privates.json` 类型 */ -export type Privates = Record +export type Privates = Record< + string, + { + /** 好友消息冷却时间,单位秒,0则无限制 */ + cd: number + /** 机器人响应模式,0-所有 2-仅回应管理员 3-仅回应别名 5-管理员无限制,非管理员别名 6-仅回应主人 */ + mode: 0 | 2 | 3 | 5 | 6 + /** 机器人别名 设置后别名+指令触发机器人 */ + alias: string[] + /** 白名单插件、功能,只有在白名单中的插件、功能才会响应 `karin-plugin-test:app.js` `karin-plugin-test:测试转发` */ + enable: string[] + /** 黑名单插件、功能,黑名单中的插件、功能不会响应 `karin-plugin-test:app.js` `karin-plugin-test:测试转发` */ + disable: string[] + /** 配置键 `Bot:selfId:userId` */ + get key(): string + } +> diff --git a/packages/core/src/utils/config/config.ts b/packages/core/src/utils/config/config.ts index b09f081..cb601ea 100644 --- a/packages/core/src/utils/config/config.ts +++ b/packages/core/src/utils/config/config.ts @@ -57,10 +57,10 @@ export const pkg = () => requireFileSync(root.karinDir + '/package.json * @param type 文件类型 用户配置/默认配置 * @param isRefresh 是否刷新缓存 */ -export const getYaml = ( +export const getYaml = ( name: T, type: 'user' | 'default', - isRefresh?: boolean + isRefresh?: boolean, ): FileListMap[T] => { const file = `${type === 'user' ? root.configPath : root.defaultConfigPath}/${name}.json` if (!fs.existsSync(file)) { @@ -75,7 +75,7 @@ export const getYaml = ( * @param name 文件名称 * @param data 配置数据 */ -export const setYaml = (name: T, data: Record) => { +export const setYaml = (name: T, data: Record) => { const file = `${root.configPath}/${name}.json` if (!fs.existsSync(file)) return false @@ -86,7 +86,7 @@ export const setYaml = (name: T, data: Record { const list = [root.htmlPath, root.consolePath] - list.forEach((file) => { + list.forEach(file => { if (fs.existsSync(file)) { fs.rmSync(file, { recursive: true, force: true }) } @@ -96,14 +96,17 @@ export const clearTemp = () => { /** * 更新日志等级 * @param level 日志等级 + * @returns 返回更新后的日志等级 */ -export const updateLevel = (level?: string) => { +export const updateLevel = (level?: string): string => { if (level) { logger.level = level - return + return level } - logger.level = process.env.LOG_LEVEL || 'info' + const newLevel = process.env.LOG_LEVEL || 'info' + logger.level = newLevel + return newLevel } watch(FILE, async (_, data) => { diff --git a/packages/core/src/utils/config/env.ts b/packages/core/src/utils/config/env.ts new file mode 100644 index 0000000..4685aaa --- /dev/null +++ b/packages/core/src/utils/config/env.ts @@ -0,0 +1,21 @@ +import path from 'node:path' +import dotenv from 'dotenv' +import chokidar from 'chokidar' + +/** + * 监听.env文件变化并自动重新加载 + */ +export const watchEnv = () => { + const targetPath = path.join(process.cwd(), '.env') + const watcher = chokidar.watch(targetPath, { persistent: true, ignoreInitial: true }) + + /** 备份RUNTIME */ + const runtime = process.env.RUNTIME + watcher.on('change', () => { + logger.info('[配置文件变动] .env') + dotenv.config({ path: targetPath, override: true }) + process.env.RUNTIME = runtime + }) +} + +watchEnv() diff --git a/packages/core/src/utils/config/index.ts b/packages/core/src/utils/config/index.ts index 823be66..6ee1480 100644 --- a/packages/core/src/utils/config/index.ts +++ b/packages/core/src/utils/config/index.ts @@ -6,3 +6,4 @@ export * from './render' export * from './adapter' export * from './default' export * from './privates' +export * from './env'