node-karin 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +57 -0
  3. package/config/defSet/App.yaml +37 -0
  4. package/config/defSet/config.yaml +43 -0
  5. package/config/defSet/group.yaml +18 -0
  6. package/config/defSet/pm2.yaml +21 -0
  7. package/config/defSet/redis.yaml +18 -0
  8. package/config/defSet/server.yaml +42 -0
  9. package/config/view/App.yaml +74 -0
  10. package/config/view/config.yaml +100 -0
  11. package/config/view/group.yaml +62 -0
  12. package/config/view/pm2.yaml +41 -0
  13. package/config/view/redis.yaml +25 -0
  14. package/config/view/server.yaml +93 -0
  15. package/lib/adapter/onebot/onebot11.d.ts +430 -0
  16. package/lib/adapter/onebot/onebot11.js +1302 -0
  17. package/lib/core/init.d.ts +0 -0
  18. package/lib/core/init.js +4 -0
  19. package/lib/core/karin.d.ts +72 -0
  20. package/lib/core/karin.js +51 -0
  21. package/lib/core/listener.d.ts +121 -0
  22. package/lib/core/listener.js +188 -0
  23. package/lib/core/plugin.app.d.ts +15 -0
  24. package/lib/core/plugin.app.js +18 -0
  25. package/lib/core/plugin.d.ts +182 -0
  26. package/lib/core/plugin.js +138 -0
  27. package/lib/core/plugin.loader.d.ts +149 -0
  28. package/lib/core/plugin.loader.js +462 -0
  29. package/lib/core/server.d.ts +26 -0
  30. package/lib/core/server.js +213 -0
  31. package/lib/db/level.d.ts +20 -0
  32. package/lib/db/level.js +38 -0
  33. package/lib/db/redis.d.ts +41 -0
  34. package/lib/db/redis.js +137 -0
  35. package/lib/db/redis_level.d.ts +113 -0
  36. package/lib/db/redis_level.js +290 -0
  37. package/lib/event/event.d.ts +138 -0
  38. package/lib/event/event.handler.d.ts +29 -0
  39. package/lib/event/event.handler.js +142 -0
  40. package/lib/event/event.js +120 -0
  41. package/lib/event/message.d.ts +102 -0
  42. package/lib/event/message.handler.d.ts +25 -0
  43. package/lib/event/message.handler.js +240 -0
  44. package/lib/event/message.js +70 -0
  45. package/lib/event/notice.d.ts +49 -0
  46. package/lib/event/notice.js +15 -0
  47. package/lib/event/request.d.ts +49 -0
  48. package/lib/event/request.js +15 -0
  49. package/lib/event/review.handler.d.ts +54 -0
  50. package/lib/event/review.handler.js +382 -0
  51. package/lib/index.d.ts +23 -0
  52. package/lib/index.js +40 -0
  53. package/lib/renderer/app.d.ts +53 -0
  54. package/lib/renderer/app.js +93 -0
  55. package/lib/renderer/base.d.ts +30 -0
  56. package/lib/renderer/base.js +71 -0
  57. package/lib/renderer/client.d.ts +30 -0
  58. package/lib/renderer/client.js +159 -0
  59. package/lib/renderer/http.d.ts +19 -0
  60. package/lib/renderer/http.js +51 -0
  61. package/lib/renderer/server.d.ts +42 -0
  62. package/lib/renderer/server.js +112 -0
  63. package/lib/renderer/wormhole.d.ts +1 -0
  64. package/lib/renderer/wormhole.js +154 -0
  65. package/lib/types/adapter.d.ts +575 -0
  66. package/lib/types/adapter.js +1 -0
  67. package/lib/types/config.d.ts +327 -0
  68. package/lib/types/config.js +1 -0
  69. package/lib/types/element.d.ts +576 -0
  70. package/lib/types/element.js +1 -0
  71. package/lib/types/index.d.ts +8 -0
  72. package/lib/types/index.js +8 -0
  73. package/lib/types/logger.d.ts +109 -0
  74. package/lib/types/logger.js +1 -0
  75. package/lib/types/onebots11.d.ts +1371 -0
  76. package/lib/types/onebots11.js +1 -0
  77. package/lib/types/plugin.d.ts +282 -0
  78. package/lib/types/plugin.js +1 -0
  79. package/lib/types/render.d.ts +111 -0
  80. package/lib/types/render.js +1 -0
  81. package/lib/types/reply.d.ts +40 -0
  82. package/lib/types/reply.js +1 -0
  83. package/lib/types/types.d.ts +898 -0
  84. package/lib/types/types.js +1 -0
  85. package/lib/utils/YamlEditor.d.ts +62 -0
  86. package/lib/utils/YamlEditor.js +208 -0
  87. package/lib/utils/button.d.ts +49 -0
  88. package/lib/utils/button.js +79 -0
  89. package/lib/utils/common.d.ts +123 -0
  90. package/lib/utils/common.js +413 -0
  91. package/lib/utils/config.d.ts +72 -0
  92. package/lib/utils/config.js +254 -0
  93. package/lib/utils/exec.d.ts +22 -0
  94. package/lib/utils/exec.js +36 -0
  95. package/lib/utils/ffmpeg.d.ts +12 -0
  96. package/lib/utils/ffmpeg.js +25 -0
  97. package/lib/utils/handler.d.ts +76 -0
  98. package/lib/utils/handler.js +102 -0
  99. package/lib/utils/logger.d.ts +3 -0
  100. package/lib/utils/logger.js +104 -0
  101. package/lib/utils/segment.d.ts +276 -0
  102. package/lib/utils/segment.js +448 -0
  103. package/lib/utils/update.d.ts +69 -0
  104. package/lib/utils/update.js +151 -0
  105. package/lib/utils/updateVersion.d.ts +33 -0
  106. package/lib/utils/updateVersion.js +145 -0
  107. package/package.json +92 -0
@@ -0,0 +1,254 @@
1
+ import fs from 'fs'
2
+ import Yaml from 'yaml'
3
+ import chokidar from 'chokidar'
4
+ /** 配置文件 */
5
+ export default new (class Cfg {
6
+ dir
7
+ _path
8
+ _pathDef
9
+ change
10
+ watcher
11
+ review
12
+ loggger
13
+ constructor () {
14
+ this.dir = process.cwd()
15
+ this._path = this.dir + '/config/config'
16
+ this._pathDef = this.dir + '/config/defSet'
17
+ /** 缓存 */
18
+ this.change = new Map()
19
+ /** 监听文件 */
20
+ this.watcher = new Map()
21
+ /** 拦截器状态 */
22
+ this.review = false
23
+ this.initCfg()
24
+ }
25
+
26
+ /** 初始化配置 */
27
+ async initCfg () {
28
+ if (!fs.existsSync(this._path)) { fs.mkdirSync(this._path) }
29
+ const files = fs.readdirSync(this._pathDef).filter(file => file.endsWith('.yaml'))
30
+ for (const file of files) {
31
+ const path = `${this._path}/${file}`
32
+ const pathDef = `${this._pathDef}/${file}`
33
+ if (!fs.existsSync(path)) { fs.copyFileSync(pathDef, path) }
34
+ }
35
+ // 创建插件文件夹文件夹
36
+ const plugins = this.getPlugins()
37
+ this.dirPath('data', plugins)
38
+ this.dirPath('temp', plugins)
39
+ this.dirPath('resources', plugins)
40
+ this.dirPath('temp/html', plugins)
41
+ this.loggger = (await import('./logger.js')).default
42
+ }
43
+
44
+ getPlugins () {
45
+ const files = fs.readdirSync('./plugins', { withFileTypes: true })
46
+ // 过滤掉非karin-plugin-开头或karin-adapter-开头的文件夹
47
+ return files.filter(file => file.isDirectory() && (file.name.startsWith('karin-plugin-') || file.name.startsWith('karin-adapter-'))).map(dir => dir.name)
48
+ }
49
+
50
+ /**
51
+ * 为每一个插件建立对应的文件夹
52
+ */
53
+ async dirPath (name, plugins) {
54
+ name = `./${name}`
55
+ if (!fs.existsSync(name)) { fs.mkdirSync(name) }
56
+ for (const plugin of plugins) {
57
+ const path = `${name}/${plugin}`
58
+ if (!fs.existsSync(path)) { fs.mkdirSync(path) }
59
+ }
60
+ }
61
+
62
+ /**
63
+ * 超时时间
64
+ */
65
+ timeout (type = 'ws') {
66
+ let timeout = 60
67
+ if (type === 'ws') {
68
+ timeout = this.Server.websocket.timeout
69
+ } else {
70
+ timeout = this.Server.grpc.timeout
71
+ }
72
+ return timeout || 60
73
+ }
74
+
75
+ /**
76
+ * Redis 配置
77
+ * 采用实时读取优化性能
78
+ */
79
+ get redis () {
80
+ const config = this.getYaml('config', 'redis', false)
81
+ const defSet = this.getYaml('defSet', 'redis', false)
82
+ const data = { ...defSet, ...config }
83
+ return data
84
+ }
85
+
86
+ /**
87
+ * 主人列表
88
+ * @returns {string[]}
89
+ */
90
+ get master () {
91
+ return this.Config.master || []
92
+ }
93
+
94
+ /**
95
+ * 管理员列表
96
+ */
97
+ get admin () {
98
+ return this.Config.admin || []
99
+ }
100
+
101
+ /** App管理 */
102
+ get App () {
103
+ const key = 'change.App'
104
+ const res = this.change.get(key)
105
+ /** 取缓存 */
106
+ if (res) { return res }
107
+ /** 取配置 */
108
+ const config = this.getYaml('config', 'App', true)
109
+ const defSet = this.getYaml('defSet', 'App', true)
110
+ const data = { ...defSet, ...config }
111
+ /** 缓存 */
112
+ this.change.set(key, data)
113
+ return data
114
+ }
115
+
116
+ /**
117
+ * 基本配置
118
+ */
119
+ get Config () {
120
+ const key = 'change.config'
121
+ const res = this.change.get(key)
122
+ /** 取缓存 */
123
+ if (res) { return res }
124
+ /** 取配置 */
125
+ const config = this.getYaml('config', 'config', true)
126
+ const defSet = this.getYaml('defSet', 'config', false)
127
+ const data = { ...defSet, ...config }
128
+ /** 缓存 */
129
+ this.change.set(key, data)
130
+ return data
131
+ }
132
+
133
+ /**
134
+ * Server 配置文档
135
+ */
136
+ get Server () {
137
+ const key = 'change.server'
138
+ /** 取缓存 */
139
+ const res = this.change.get(key)
140
+ if (res) { return res }
141
+ /** 取配置 */
142
+ const config = this.getYaml('config', 'server', true)
143
+ const defSet = this.getYaml('defSet', 'server', false)
144
+ const data = { ...defSet, ...config }
145
+ /** 缓存 */
146
+ this.change.set(key, data)
147
+ return data
148
+ }
149
+
150
+ /**
151
+ * packageon
152
+ * 实时获取packageon文件
153
+ */
154
+ get package () {
155
+ const data = fs.readFileSync('./package.json', 'utf8')
156
+ const pack = JSON.parse(data)
157
+ return pack
158
+ }
159
+
160
+ /**
161
+ * 获取群配置
162
+ */
163
+ group (group_id = '') {
164
+ const key = 'change.group'
165
+ /** 取缓存 */
166
+ let res = this.change.get(key)
167
+ if (res) {
168
+ res = { ...res.defCfg.default, ...res.Config.default, ...(res.Config[group_id] || {}) }
169
+ return res
170
+ }
171
+ /** 取配置 */
172
+ const Config = this.getYaml('config', 'group')
173
+ const defCfg = this.getYaml('defSet', 'group')
174
+ const data = { Config, defCfg }
175
+ /** 缓存 */
176
+ res = this.change.set(key, data)
177
+ res = { ...defCfg.default, ...Config.default, ...(Config[group_id] || {}) }
178
+ return res
179
+ }
180
+
181
+ /**
182
+ * 获取配置yaml
183
+ */
184
+ getYaml (type, name, isWatch = false) {
185
+ /** 文件路径 */
186
+ const file = `./config/${type}/${name}.yaml`
187
+ /** 读取文件 */
188
+ const data = Yaml.parse(fs.readFileSync(file, 'utf8'))
189
+ /** 监听文件 */
190
+ if (isWatch) { this.watch(type, name, file) }
191
+ return data
192
+ }
193
+
194
+ /**
195
+ * 监听配置文件
196
+ * @param {'defSet'|'config'} type 类型
197
+ * @param {string} name 文件名称 不带后缀
198
+ * @param {string} file 文件路径
199
+ */
200
+ async watch (type, name, file) {
201
+ const key = `change.${name}`
202
+ /** 已经监听过了 */
203
+ const res = this.change.get(key)
204
+ if (res) { return true }
205
+ /** 监听文件 */
206
+ const watcher = chokidar.watch(file)
207
+ /** 监听文件变化 */
208
+ watcher.on('change', () => {
209
+ this.change.delete(key)
210
+ this.loggger.mark(`[修改配置文件][${type}][${name}]`)
211
+ /** 文件修改后调用对应的方法 */
212
+ switch (`change_${name}`) {
213
+ case 'change_App':
214
+ this.change_App()
215
+ break
216
+ case 'change_config':
217
+ this.change_config()
218
+ break
219
+ case 'change_group':
220
+ this.change_group()
221
+ break
222
+ }
223
+ })
224
+ /** 缓存 防止重复监听 */
225
+ this.watcher.set(key, watcher)
226
+ }
227
+
228
+ async change_App () {
229
+ await this.#review()
230
+ }
231
+
232
+ async change_config () {
233
+ /** 修改日志等级 */
234
+ this.loggger.level = this.Config.log_level
235
+ await this.#review()
236
+ // if (this.Server.HotUpdate) {
237
+ // const { Bot } = await import('../index.js')
238
+ // Bot.emit('restart_http', {})
239
+ // Bot.emit('restart_grpc', {})
240
+ // }
241
+ }
242
+
243
+ async change_group () {
244
+ await this.#review()
245
+ }
246
+
247
+ async #review () {
248
+ // if (this.review) return
249
+ // this.review = true
250
+ // const review = await import('../event/review')
251
+ // review.default.main()
252
+ // this.review = false
253
+ }
254
+ })()
@@ -0,0 +1,22 @@
1
+ /**
2
+ * 执行 shell 命令
3
+ * @param cmd 命令
4
+ * @param log 是否打印日志
5
+ * @param options 选项
6
+ */
7
+ export declare const exec: (cmd: string, log?: boolean, options?: {
8
+ cwd: string;
9
+ encoding: string;
10
+ }) => Promise<{
11
+ /**
12
+ * - 执行状态
13
+ */
14
+ status: 'ok' | 'failed';
15
+ /**
16
+ * - 错误信息
17
+ */
18
+ error: Error | null;
19
+ stdout: string | '';
20
+ stderr: string | '';
21
+ }>;
22
+ export default exec;
@@ -0,0 +1,36 @@
1
+ import logger from './logger.js'
2
+ import { exec as execCmd } from 'child_process'
3
+ /**
4
+ * 执行 shell 命令
5
+ * @param cmd 命令
6
+ * @param log 是否打印日志
7
+ * @param options 选项
8
+ */
9
+ export const exec = (cmd, log = true, options = { cwd: process.cwd(), encoding: 'utf-8' }) => {
10
+ return new Promise(resolve => {
11
+ const logMessage = (level, message) => {
12
+ if (log) { logger[level](message) }
13
+ }
14
+ const logType = (status) => {
15
+ switch (status) {
16
+ case '开始执行':
17
+ return logger.yellow('[exec][开始执行]')
18
+ case 'ok':
19
+ return logger.green('[exec][执行成功]')
20
+ case 'failed':
21
+ return logger.red('[exec][执行失败]')
22
+ }
23
+ }
24
+ const formatMessage = (status, details) => [logType(status), `cmd: ${cmd}`, `cwd: ${options.cwd || process.cwd()}`, details, '--------'].join('\n')
25
+ logMessage('info', formatMessage('开始执行', ''))
26
+ execCmd(cmd, options, (error, stdout, stderr) => {
27
+ if (error) {
28
+ logMessage('error', formatMessage('failed', `Error: ${error.message || error.stack || error.toString()}`))
29
+ return resolve({ status: 'failed', error, stdout, stderr })
30
+ }
31
+ logMessage('mark', formatMessage('ok', `stdout: ${stdout}\nstderr: ${stderr}`))
32
+ resolve({ status: 'ok', error, stdout, stderr })
33
+ })
34
+ })
35
+ }
36
+ export default exec
@@ -0,0 +1,12 @@
1
+ /**
2
+ * 执行 ffmpeg 命令
3
+ */
4
+ export default function ffmpeg(): Promise<false | ((cmd: string, log?: boolean, options?: {
5
+ cwd: string;
6
+ encoding: string;
7
+ }) => Promise<{
8
+ status: "failed" | "ok";
9
+ error: Error | null;
10
+ stdout: string;
11
+ stderr: string;
12
+ }>)>;
@@ -0,0 +1,25 @@
1
+ import exec from './exec.js'
2
+ import logger from './logger.js'
3
+ import Config from './config.js'
4
+ /**
5
+ * 执行 ffmpeg 命令
6
+ */
7
+ export default async function ffmpeg () {
8
+ let ffmpeg = 'ffmpeg'
9
+ const { status } = await exec('ffmpeg -version', false)
10
+ if (status !== 'ok') {
11
+ logger.debug('ffmpeg 未安装,开始尝试读取配置文件是否存在ffmpeg路径')
12
+ const ffmpegPath = Config.Config.ffmpeg_path
13
+ if (!ffmpegPath) {
14
+ logger.warn('ffmpeg 未安装,请安装 ffmpeg 或手动配置 ffmpeg 路径后重启')
15
+ return false
16
+ }
17
+ ffmpeg = `"${ffmpegPath}"`
18
+ }
19
+ // 返回函数
20
+ return async (cmd, log = true, options = { cwd: process.cwd(), encoding: 'utf-8' }) => {
21
+ cmd = cmd.replace(/^ffmpeg/, '').trim()
22
+ cmd = `${ffmpeg} ${cmd}`
23
+ return await exec(cmd, log, options)
24
+ }
25
+ }
@@ -0,0 +1,76 @@
1
+ import Plugin from '../core/plugin.js';
2
+ import { dirName, fileName } from '../types/plugin.js';
3
+ /**
4
+ * 事件处理器类
5
+ */
6
+ declare const _default: {
7
+ events: {
8
+ [key: string]: {
9
+ /**
10
+ * - 文件信息
11
+ */
12
+ file: {
13
+ /**
14
+ * - 插件包名称
15
+ */
16
+ dir: dirName;
17
+ /**
18
+ * - 文件名称
19
+ */
20
+ name: fileName;
21
+ };
22
+ /**
23
+ * - 事件class
24
+ */
25
+ App: new () => Plugin;
26
+ /**
27
+ * - 事件键
28
+ */
29
+ key: string;
30
+ /**
31
+ * - 事件处理函数名称
32
+ */
33
+ fnc: string;
34
+ /**
35
+ * - 优先级
36
+ */
37
+ priority: number;
38
+ }[];
39
+ };
40
+ /**
41
+ * 添加事件处理器
42
+ * @param {Object} config 配置对象
43
+ * @param {string} config.name 处理器名称
44
+ * @param {string} config.dir 处理器所在目录
45
+ * @param {Function} config.App 应用构造函数
46
+ * @param {Object} config.Class 类配置
47
+ */
48
+ add({ name, dir, App, Class }: {
49
+ dir: dirName;
50
+ name: fileName;
51
+ App: new () => Plugin;
52
+ Class: Plugin;
53
+ }): void;
54
+ /**
55
+ * 删除事件处理器
56
+ */
57
+ del({ dir, name, key, }: {
58
+ dir: dirName | '';
59
+ name: fileName | '';
60
+ /**
61
+ * 事件键 未传入则删除所有处理器
62
+ */
63
+ key: string | '';
64
+ }): boolean;
65
+ /**
66
+ * 调用事件处理器
67
+ * @param key 事件键
68
+ * @param args 自定义参数 一般用来传递e之类的
69
+ */
70
+ call(key: string, args?: {}): Promise<any>;
71
+ /**
72
+ * 检查是否存在指定键的事件处理器
73
+ */
74
+ has(key: string): boolean;
75
+ };
76
+ export default _default;
@@ -0,0 +1,102 @@
1
+ import util from 'util'
2
+ import lodash from 'lodash'
3
+ import logger from './logger.js'
4
+ /**
5
+ * 事件处理器类
6
+ */
7
+ export default new (class EventHandler {
8
+ events
9
+ constructor () {
10
+ this.events = {}
11
+ }
12
+
13
+ /**
14
+ * 添加事件处理器
15
+ * @param {Object} config 配置对象
16
+ * @param {string} config.name 处理器名称
17
+ * @param {string} config.dir 处理器所在目录
18
+ * @param {Function} config.App 应用构造函数
19
+ * @param {Object} config.Class 类配置
20
+ */
21
+ add ({ name, dir, App, Class }) {
22
+ for (const cfg of Class.handler) {
23
+ const { key = '', fnc = '', priority = 2000 } = cfg
24
+ if (!key) {
25
+ return logger.error(`[Handler][Add]: [${name}] 缺少 key`)
26
+ }
27
+ if (!fnc) {
28
+ return logger.error(`[Handler][Add]: [${name}] 缺少 fnc`)
29
+ }
30
+ logger.debug(`[Handler][Reg]: [${name}][${key}]`)
31
+ if (!Array.isArray(this.events[key])) { this.events[key] = [] }
32
+ this.events[key].push({ file: { name, dir }, App, key, fnc, priority })
33
+ this.events[key] = lodash.orderBy(this.events[key], ['priority'], ['asc'])
34
+ }
35
+ }
36
+
37
+ /**
38
+ * 删除事件处理器
39
+ */
40
+ del ({ dir = '', name = '', key = '' }) {
41
+ /** 这里是删除所有 全部重新初始化 */
42
+ if (!key && !dir && !name) {
43
+ this.events = {}
44
+ return true
45
+ }
46
+ /** 热重载 删除指定目录 */
47
+ if (!key) {
48
+ for (const v of Object.keys(this.events)) {
49
+ this.events[v] = this.events[v].filter(v => v.file.dir !== dir || v.file.name !== name)
50
+ // 如果处理器为空则删除键
51
+ if (!this.events[v].length) {
52
+ delete this.events[v]
53
+ } else {
54
+ this.events[v] = lodash.orderBy(this.events[v], ['priority'], ['asc'])
55
+ }
56
+ }
57
+ return true
58
+ }
59
+ if (!this.events[key]) { return false }
60
+ this.events[key] = this.events[key].filter(v => v.file.dir !== dir || v.file.name !== name)
61
+ this.events[key] = lodash.orderBy(this.events[key], ['priority'], ['asc'])
62
+ return true
63
+ }
64
+
65
+ /**
66
+ * 调用事件处理器
67
+ * @param key 事件键
68
+ * @param args 自定义参数 一般用来传递e之类的
69
+ */
70
+ async call (key, args = {}) {
71
+ let ret
72
+ for (const v of this.events[key] || []) {
73
+ const App = new v.App()
74
+ if ('e' in args && args.e) { App.e = args.e }
75
+ let done = true
76
+ // 标记函数,用于标记处理器是否执行成功,由处理器自行调用,如果未调用则认为处理器未执行成功
77
+ const reject = (msg = '') => {
78
+ if (msg) { logger.mark(`[Handler][Reject]: [${v.file.dir}][${v.file.name}][${key}] ${msg}`) }
79
+ done = false
80
+ }
81
+ try {
82
+ ret = await App[v.fnc](args, reject)
83
+ if (util.types.isPromise(ret)) { ret = await ret }
84
+ if (done) {
85
+ logger.mark(`[Handler][Done]: [${v.file.dir}][${v.file.name}][${key}]`)
86
+ return ret
87
+ }
88
+ } catch (e) {
89
+ // 产生错误继续下一个处理器
90
+ logger.error(`[Handler][Error]: [${v.file.dir}][${v.file.name}][${key}] ${e}`)
91
+ }
92
+ }
93
+ return ret
94
+ }
95
+
96
+ /**
97
+ * 检查是否存在指定键的事件处理器
98
+ */
99
+ has (key) {
100
+ return !!this.events[key]
101
+ }
102
+ })()
@@ -0,0 +1,3 @@
1
+ import log4js from 'log4js';
2
+ declare const logger: log4js.Logger;
3
+ export default logger;
@@ -0,0 +1,104 @@
1
+ import fs from 'fs'
2
+ import chalk from 'chalk'
3
+ import log4js from 'log4js'
4
+ import Cfg from './config.js'
5
+ const logsDir = './logs'
6
+ if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir) }
7
+ const { log_level, log_days_Keep, log4jsCfg } = Cfg.Config
8
+ const level = log_level || log4jsCfg.level || 'info'
9
+ const daysToKeep = log_days_Keep || log4jsCfg.daysToKeep || 7
10
+ const { overall, fragments, maxLogSize } = log4jsCfg
11
+ const defaultOptions = { appenders: ['console'], level, enableCallStack: process.env.KarinMode === 'dev' }
12
+ const options = {
13
+ appenders: {
14
+ console: {
15
+ type: 'console',
16
+ layout: {
17
+ type: 'pattern',
18
+ pattern: `%[[Karin][%d{hh:mm:ss.SSS}][%4.4p]%] ${process.env.KarinMode === 'dev' ? '[%f{3}:%l] ' : ''}%m`,
19
+ },
20
+ },
21
+ },
22
+ categories: { default: defaultOptions },
23
+ }
24
+ if (overall) {
25
+ defaultOptions.appenders.unshift('overall')
26
+ options.appenders.overall = {
27
+ /** 输出到文件 */
28
+ type: 'file',
29
+ filename: 'logs/logger',
30
+ pattern: 'yyyy-MM-dd.log',
31
+ /** 日期后缀 */
32
+ keepFileExt: true,
33
+ /** 日志文件名中包含日期模式 */
34
+ alwaysIncludePattern: true,
35
+ /** 日志文件保留天数 */
36
+ daysToKeep,
37
+ /** 日志输出格式 */
38
+ layout: {
39
+ type: 'pattern',
40
+ pattern: '[%d{hh:mm:ss.SSS}][%4.4p] %m',
41
+ },
42
+ }
43
+ }
44
+ if (fragments) {
45
+ defaultOptions.appenders.unshift('fragments')
46
+ options.appenders.fragments = {
47
+ type: 'file',
48
+ filename: 'logs/app.log',
49
+ pattern: 'MM-dd.log',
50
+ keepFileExt: true,
51
+ alwaysIncludePattern: true,
52
+ daysToKeep,
53
+ maxLogSize: (maxLogSize || 30) * 1024 * 1024,
54
+ /** 最大文件数 */
55
+ numBackups: 9999999,
56
+ /** 日志输出格式 */
57
+ layout: {
58
+ type: 'pattern',
59
+ pattern: '[%d{hh:mm:ss.SSS}][%4.4p] %m',
60
+ },
61
+ }
62
+ }
63
+ log4js.configure(options)
64
+ const logger = log4js.getLogger('default')
65
+ logger.chalk = chalk
66
+ logger.red = chalk.red
67
+ logger.green = chalk.green
68
+ logger.yellow = chalk.yellow
69
+ logger.blue = chalk.blue
70
+ logger.magenta = chalk.magenta
71
+ logger.cyan = chalk.cyan
72
+ logger.white = chalk.white
73
+ logger.gray = chalk.gray
74
+ logger.violet = chalk.hex('#868ECC')
75
+ logger.fnc = chalk.hex(Cfg.Config.log_color || '#FFFF00')
76
+ logger.bot = (level, id, ...args) => {
77
+ switch (level) {
78
+ case 'trace':
79
+ logger.trace(logger.violet(`[Bot:${id}] `), ...args)
80
+ break
81
+ case 'debug':
82
+ logger.debug(logger.violet(`[Bot:${id}] `), ...args)
83
+ break
84
+ case 'mark':
85
+ logger.mark(logger.violet(`[Bot:${id}] `), ...args)
86
+ break
87
+ case 'info':
88
+ logger.info(logger.violet(`[Bot:${id}] `), ...args)
89
+ break
90
+ case 'warn':
91
+ logger.warn(logger.violet(`[Bot:${id}] `), ...args)
92
+ break
93
+ case 'error':
94
+ logger.error(logger.violet(`[Bot:${id}] `), ...args)
95
+ break
96
+ case 'fatal':
97
+ logger.fatal(logger.violet(`[Bot:${id}] `), ...args)
98
+ break
99
+ default:
100
+ logger.info(logger.violet(`[Bot:${id}] `), ...args)
101
+ }
102
+ }
103
+ global.logger = logger
104
+ export default logger