@layoutkit/bree-core 1.0.6

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.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # bree-core
2
+
3
+ 内部 Bree 调度封装包。
4
+
5
+ ## 安装
6
+
7
+ npm install @company/bree-core
8
+
9
+ ## 使用
10
+
11
+ ```js
12
+ import { Scheduler } from '@company/bree-core';
13
+
14
+ const scheduler = new Scheduler({
15
+ jobsPath: './jobs'
16
+ });
17
+
18
+ scheduler.start();
19
+ ```
20
+
21
+ ## 打包
22
+
23
+ npm install
24
+ npm run build
25
+
26
+ 生成 dist/index.js
package/dist/index.js ADDED
@@ -0,0 +1,850 @@
1
+ import knex from 'knex';
2
+ import dotenv from 'dotenv';
3
+ import crypto from 'node:crypto';
4
+ import ExcelJS from 'exceljs';
5
+ import path from 'node:path';
6
+ import nodemailer from 'nodemailer';
7
+ import { createClient } from 'redis';
8
+ import Bree from 'bree';
9
+ import fs from 'node:fs';
10
+ import { fileURLToPath } from 'node:url';
11
+ import winston from 'winston';
12
+ import 'winston-daily-rotate-file';
13
+ import { parentPort, workerData } from 'node:worker_threads';
14
+
15
+ const ALGORITHM_MAP$1 = {
16
+ 16: 'aes-128-ecb',
17
+ 24: 'aes-192-ecb',
18
+ 32: 'aes-256-ecb'
19
+ };
20
+
21
+ const encrypt$1 = (data, key) => {
22
+ // key 必须 16 / 24 / 32 字节
23
+ const keyBuf = Buffer.from(key, 'utf8');
24
+ const cipher = crypto.createCipheriv(ALGORITHM_MAP$1[keyBuf.length], keyBuf, null);
25
+ cipher.setAutoPadding(true); // PKCS7
26
+ const encrypted = Buffer.concat([
27
+ cipher.update(data),
28
+ cipher.final()
29
+ ]);
30
+ return encrypted
31
+ };
32
+
33
+ const decrypt$1 = (data, key) => {
34
+ const keyBuf = Buffer.from(key, 'utf8');
35
+ const decipher = crypto.createDecipheriv(ALGORITHM_MAP$1[keyBuf.length], keyBuf, null);
36
+ decipher.setAutoPadding(true);
37
+ const decrypted = Buffer.concat([
38
+ decipher.update(data),
39
+ decipher.final()
40
+ ]);
41
+ return decrypted
42
+ };
43
+
44
+ /**
45
+ * AES解密
46
+ * 对应 Java:
47
+ * AesUtil.decrypt(String data, String key)
48
+ *
49
+ * @param {string} data Base64密文
50
+ * @param {string} key AES密钥(16/24/32字节)
51
+ * @returns {string} 明文
52
+ */
53
+ const decryptString$1 = (data, key) => {
54
+ const keyBuf = Buffer.from(key, 'utf8');
55
+ const decipher = crypto.createDecipheriv(ALGORITHM_MAP$1[keyBuf.length], keyBuf, null);
56
+ decipher.setAutoPadding(true);
57
+ const decrypted = Buffer.concat([
58
+ decipher.update(Buffer.from(data, 'base64')),
59
+ decipher.final()
60
+ ]);
61
+ return decrypted.toString('utf8')
62
+ };
63
+
64
+ var aes$1 = { encrypt: encrypt$1, decrypt: decrypt$1, decryptString: decryptString$1 };
65
+
66
+ dotenv.config();
67
+
68
+ let db$1 = null;
69
+ const init$2 = async () => {
70
+ const connectionString = process.env.DB_CONNECTION_STRING;
71
+ const aesKey = process.env.DB_AES_KEY;
72
+ try {
73
+ const decryptedConnectionString = aes$1.decryptString(connectionString, aesKey);
74
+ const connectionParams = decryptedConnectionString.split(';').reduce((acc, param) => {
75
+ const [key, value] = param.split('=');
76
+ acc[key] = value;
77
+ return acc
78
+ }, {});
79
+ db$1 = knex({
80
+ client: 'mssql',
81
+ connection: {
82
+ user: connectionParams.user,
83
+ password: connectionParams.password,
84
+ server: connectionParams.server,
85
+ database: connectionParams.database,
86
+ options: {
87
+ encrypt: false
88
+ }
89
+ }
90
+ });
91
+
92
+ // 等待数据库真实连接
93
+ await db$1.raw('SELECT 1');
94
+ console.log('database initialized');
95
+ return db$1
96
+ } catch (error) {
97
+ await close();
98
+
99
+ throw error
100
+ }
101
+ };
102
+
103
+ const close = async () => {
104
+ if (db$1) {
105
+ await db$1.destroy();
106
+ db$1 = null;
107
+ }
108
+ };
109
+
110
+ var database = {
111
+ init: init$2,
112
+ close
113
+ };
114
+
115
+ /**
116
+ * 内部:构建 sheet columns:[{ header: 'ID', key: 'id', width: 10 }]
117
+ */
118
+ const buildSheet = (workbook, columns, data) => {
119
+ const sheet = workbook.addWorksheet('sheet1');
120
+ sheet.columns = columns;
121
+ for (const item of data) {
122
+ sheet.addRow(item);
123
+ }
124
+ return sheet
125
+ };
126
+
127
+ /**
128
+ * 小/中数据:生成 Excel 文件(落盘)
129
+ * 适合:< 5w 行
130
+ */
131
+ const createExcel = async (columns, data, fileName = 'report') => {
132
+ const workbook = new ExcelJS.Workbook();
133
+ buildSheet(workbook, columns, data);
134
+ const filePath = path.join(process.cwd(), `${fileName}.xlsx`);
135
+ await workbook.xlsx.writeFile(filePath);
136
+ return filePath
137
+ };
138
+
139
+ /**
140
+ * 邮件专用:生成 Buffer(不落盘)
141
+ * 适合:中小数据
142
+ */
143
+ const createBufferExcel = async (columns, data) => {
144
+ const workbook = new ExcelJS.Workbook();
145
+ buildSheet(workbook, columns, data);
146
+ return await workbook.xlsx.writeBuffer()
147
+ };
148
+
149
+ /**
150
+ * 大数据(核心优化):流式写入(不爆内存)
151
+ * 适合:10w ~ 100w+
152
+ */
153
+ const createStreamExcel = async (columns, data, fileName = 'report') => {
154
+ const filePath = path.join(process.cwd(), `${fileName}.xlsx`);
155
+ const workbook = new ExcelJS.stream.xlsx.WorkbookWriter({
156
+ filename: filePath,
157
+ useStyles: false,
158
+ useSharedStrings: true
159
+ });
160
+
161
+ const sheet = workbook.addWorksheet('Report');
162
+ sheet.columns = columns;
163
+ for (const item of data) {
164
+ sheet.addRow(item).commit();
165
+ }
166
+ await workbook.commit();
167
+ return filePath
168
+ };
169
+
170
+ /**
171
+ * 🚀 统一入口(推荐用这个)
172
+ */
173
+ const exportExcel = async ({
174
+ mode = 'file', // file | buffer | stream
175
+ columns,
176
+ data,
177
+ fileName = 'report'
178
+ }) => {
179
+ switch (mode) {
180
+ case 'buffer':
181
+ return await createBufferExcel(columns, data)
182
+
183
+ case 'stream':
184
+ return await createStreamExcel(columns, data, fileName)
185
+
186
+ default:
187
+ return await createExcel(columns, data, fileName)
188
+ }
189
+ };
190
+
191
+ var excelUtil = {
192
+ exportExcel,
193
+ createExcel,
194
+ createBufferExcel,
195
+ createStreamExcel
196
+ };
197
+
198
+ let transporter = null;
199
+ let from = '';
200
+ const init$1 = () => {
201
+ from = `"${process.env.MAIL_USERNAME}" <${process.env.MAIL_ACCOUNT}>`;
202
+ transporter = nodemailer.createTransport({
203
+ host: process.env.MAIL_HOST, // 或公司邮箱 SMTP
204
+ port: Number(process.env.MAIL_PORT),
205
+ secure: true,
206
+ auth: {
207
+ user: process.env.MAIL_ACCOUNT,
208
+ pass: process.env.MAIL_PASSWORD // 注意不是密码
209
+ }
210
+ });
211
+ };
212
+
213
+ const send = async (subject, toUser = '', copyUser = '', content = '', filePath = []) => {
214
+ await transporter.sendMail({
215
+ from: from,
216
+ to: toUser.split(',').map(i => i.trim()).filter(Boolean),
217
+ cc: copyUser.split(',').map(i => i.trim()).filter(Boolean),
218
+ subject: subject,
219
+ text: content,
220
+ attachments: filePath.map(file => {
221
+ const filename = path.basename(file); // ⭐ 核心:自动截取文件名
222
+ return {
223
+ path: file,
224
+ filename
225
+ }
226
+ })
227
+ });
228
+ };
229
+
230
+ var mailUtil = {
231
+ init: init$1,
232
+ send
233
+ };
234
+
235
+ let client = null;
236
+
237
+ async function createRedisClient() {
238
+ const redis = createClient({
239
+ socket: {
240
+ host: process.env.REDIS_HOST,
241
+ port: Number(process.env.REDIS_PORT),
242
+ reconnectStrategy(retries) {
243
+ console.log(`Redis 重连 ${retries}`);
244
+
245
+ // 超过 2 次停止重连
246
+ if (retries > 3) {
247
+ return new Error('Redis 重连失败')
248
+ }
249
+
250
+ return Math.min(retries * 1000, 5000)
251
+ }
252
+ },
253
+ RESP: 2, // ⭐关键
254
+ username: process.env.REDIS_USERNAME || undefined,
255
+ password: process.env.REDIS_PASSWORD || undefined,
256
+ database: Number(process.env.REDIS_DB || 0)
257
+ });
258
+
259
+ redis.on('connect', () => {
260
+ console.log('Redis 正在连接...');
261
+ });
262
+
263
+ redis.on('ready', () => {
264
+ console.log('Redis 已连接');
265
+ });
266
+
267
+ redis.on('reconnecting', () => {
268
+ console.log('Redis 重连中...');
269
+ });
270
+
271
+ redis.on('end', () => {
272
+ console.log('Redis 已断开');
273
+ });
274
+
275
+ redis.on('error', (err) => {
276
+ console.error('Redis异常:', err.message);
277
+ });
278
+
279
+ await redis.connect();
280
+
281
+ return redis
282
+ }
283
+
284
+ async function getRedis() {
285
+ if (!client) {
286
+ client = await createRedisClient();
287
+ }
288
+
289
+ return client
290
+ }
291
+
292
+ async function closeRedis() {
293
+ if (client) {
294
+ await client.quit();
295
+ client = null;
296
+ }
297
+ }
298
+
299
+ class RedisHelper {
300
+ async set(key, value, expireSeconds = null) {
301
+ const redis = await getRedis();
302
+
303
+ const data =
304
+ typeof value === 'object'
305
+ ? JSON.stringify(value)
306
+ : String(value);
307
+
308
+ if (expireSeconds) {
309
+ return await redis.set(key, data, {
310
+ EX: expireSeconds
311
+ })
312
+ }
313
+
314
+ return await redis.set(key, data)
315
+ }
316
+
317
+ async get(key) {
318
+ const redis = await getRedis();
319
+
320
+ const value = await redis.get(key);
321
+
322
+ if (!value) return null
323
+
324
+ try {
325
+ return JSON.parse(value)
326
+ } catch {
327
+ return value
328
+ }
329
+ }
330
+
331
+ async del(key) {
332
+ const redis = await getRedis();
333
+ return await redis.del(key)
334
+ }
335
+
336
+ async exists(key) {
337
+ const redis = await getRedis();
338
+ return (await redis.exists(key)) === 1
339
+ }
340
+
341
+ async expire(key, seconds) {
342
+ const redis = await getRedis();
343
+ return await redis.expire(key, seconds)
344
+ }
345
+
346
+ async ttl(key) {
347
+ const redis = await getRedis();
348
+ return await redis.ttl(key)
349
+ }
350
+
351
+ async incr(key) {
352
+ const redis = await getRedis();
353
+ return await redis.incr(key)
354
+ }
355
+
356
+ async decr(key) {
357
+ const redis = await getRedis();
358
+ return await redis.decr(key)
359
+ }
360
+
361
+ async hSet(key, field, value) {
362
+ const redis = await getRedis();
363
+
364
+ return await redis.hSet(
365
+ key,
366
+ field,
367
+ typeof value === 'object'
368
+ ? JSON.stringify(value)
369
+ : String(value)
370
+ )
371
+ }
372
+
373
+ async hGet(key, field) {
374
+ const redis = await getRedis();
375
+
376
+ const value = await redis.hGet(key, field);
377
+
378
+ if (!value) return null
379
+
380
+ try {
381
+ return JSON.parse(value)
382
+ } catch {
383
+ return value
384
+ }
385
+ }
386
+
387
+ async hGetAll(key) {
388
+ const redis = await getRedis();
389
+ return await redis.hGetAll(key)
390
+ }
391
+
392
+ async lPush(key, value) {
393
+ const redis = await getRedis();
394
+
395
+ return await redis.lPush(
396
+ key,
397
+ JSON.stringify(value)
398
+ )
399
+ }
400
+
401
+ async rPop(key) {
402
+ const redis = await getRedis();
403
+
404
+ const value = await redis.rPop(key);
405
+
406
+ return value
407
+ ? JSON.parse(value)
408
+ : null
409
+ }
410
+
411
+ async close() {
412
+ await closeRedis();
413
+ }
414
+ }
415
+
416
+ var redis = new RedisHelper();
417
+
418
+ const __filename$1 = fileURLToPath(import.meta.url);
419
+ const __dirname$1 = path.dirname(__filename$1);
420
+
421
+ const { combine: combine$2, timestamp: timestamp$2, printf: printf$2 } = winston.format;
422
+ const logFormat$2 = printf$2(({ timestamp, level, message }) => {
423
+ return `[${timestamp}] [${level.toUpperCase()}] ${message}`
424
+ });
425
+
426
+ const breeLogger = winston.createLogger({
427
+ level: 'info',
428
+ format: combine$2(
429
+ timestamp$2({ format: 'YYYY-MM-DD HH:mm:ss' }),
430
+ logFormat$2
431
+ ),
432
+ transports: [
433
+ new winston.transports.Console(),
434
+ new winston.transports.DailyRotateFile({
435
+ dirname: 'logs',
436
+ filename: 'worker-%DATE%.log',
437
+ datePattern: 'YYYY-MM-DD',
438
+ maxSize: '20m',
439
+ maxFiles: '30d'
440
+ })
441
+ ]
442
+ });
443
+
444
+ /**
445
+ * worker日志
446
+ */
447
+ const worker = (jobName, message) => {
448
+ breeLogger.info(`[${jobName}] ${message}`);
449
+ };
450
+
451
+ /**
452
+ * error日志
453
+ */
454
+ const error$1 = (jobName, err) => {
455
+ breeLogger.error(`[${jobName}] ${err?.stack || err?.message || err}`);
456
+ };
457
+ var blogger = { worker, error: error$1 };
458
+
459
+ path.resolve(__dirname$1, '../../');
460
+
461
+ let bree = null;
462
+ let db = null;
463
+ let jobsRoot = null;
464
+
465
+ // 让使用者通过环境变量或配置指定 jobs 目录
466
+ const getJobsRoot = () => {
467
+ if (jobsRoot) return jobsRoot
468
+
469
+ // 多种方式获取 jobs 目录
470
+ // 1. 环境变量
471
+ if (process.env.BREE_JOBS_PATH) {
472
+ jobsRoot = path.resolve(process.env.BREE_JOBS_PATH);
473
+ return jobsRoot
474
+ }
475
+
476
+ // 2. 使用当前工作目录(项目根目录)
477
+ const cwd = process.cwd();
478
+ const possiblePaths = [
479
+ path.join(cwd, 'src/jobs'),
480
+ path.join(cwd, 'jobs'),
481
+ path.join(cwd, 'dist/jobs'),
482
+ ];
483
+
484
+ for (const p of possiblePaths) {
485
+ if (fs.existsSync(p)) {
486
+ jobsRoot = p;
487
+ return jobsRoot
488
+ }
489
+ }
490
+
491
+ // 3. 默认使用当前工作目录下的 src/jobs
492
+ jobsRoot = path.join(cwd, 'src/jobs');
493
+ console.warn(`Jobs directory not found, using default: ${jobsRoot}`);
494
+ return jobsRoot
495
+ };
496
+
497
+ const createBree = () => {
498
+ const jobsPath = getJobsRoot();
499
+ // 确保 jobs 目录存在(创建警告但不自动创建,因为这是使用者的责任)
500
+ if (!fs.existsSync(jobsPath)) {
501
+ console.warn(`⚠️ Jobs directory not found: ${jobsPath}`);
502
+ console.warn(` Please create it or set BREE_JOBS_PATH environment variable`);
503
+ }
504
+ const instance = new Bree({
505
+ hasSeconds: true,
506
+ root: jobsPath,
507
+ errorHandler: async (error, workerMetadata) => {
508
+ if (workerMetadata?.threadId) {
509
+ blogger.worker(workerMetadata.name,
510
+ `There was an error while running a worker ${workerMetadata.name} with thread ID: ${workerMetadata.threadId}`);
511
+ } else {
512
+ blogger.worker(workerMetadata.name,
513
+ `There was an error while running a worker ${workerMetadata.name}`);
514
+ }
515
+
516
+ blogger.error(workerMetadata?.name, error);
517
+ if (error?.message?.indexOf('exited with code') > -1) return
518
+ const job = instance.config.jobs.find(x => x.name === workerMetadata?.name);
519
+ const workerData = job?.worker?.workerData;
520
+ if (workerData) {
521
+ await db('Sys_BreeJobs')
522
+ .where('ID', workerData.id)
523
+ .update({
524
+ 'ResultStatus': 1,
525
+ 'ErrorMessage': error?.stack
526
+ });
527
+ }
528
+ }
529
+ });
530
+
531
+ instance.on('worker created', (name) => {
532
+ console.log('worker created', name);
533
+ blogger.worker(name, 'worker created');
534
+ });
535
+
536
+ instance.on('worker deleted', (name) => {
537
+ console.log('worker deleted', name);
538
+ blogger.worker(name, 'worker deleted');
539
+ });
540
+
541
+ return instance
542
+ };
543
+
544
+ const getBree = () => {
545
+ return bree
546
+ };
547
+
548
+ const reset = async (job, startStatus) => {
549
+ await bree.stop(job.name);
550
+ const index = bree.config.jobs.findIndex(x => x.name === job.name);
551
+ if (index !== -1) bree.config.jobs.splice(index, 1);
552
+ await bree.add(job);
553
+ if (startStatus) await bree.start(job.name);
554
+ };
555
+
556
+ const remove = async (name) => {
557
+ await bree.stop(name);
558
+
559
+ // 删除运行中的 worker 貌似不需要
560
+ // delete bree.workers.get(name)
561
+
562
+ const index = bree.config.jobs.findIndex(x => x.name === name);
563
+ if (index !== -1) bree.config.jobs.splice(index, 1);
564
+ };
565
+
566
+ const create = async (job) => {
567
+ if (bree.config.jobs.some(x => x.name === job.name))
568
+ return
569
+
570
+ await bree.add(job);
571
+ };
572
+
573
+ // 启动任务
574
+ const start = async (name) => {
575
+ await bree.start(name);
576
+ };
577
+ // 停止任务
578
+ const stop = async (name) => {
579
+ await bree.stop(name);
580
+ };
581
+ // 执行一次任务
582
+ const run = async (name) => {
583
+ await bree.run(name);
584
+ };
585
+
586
+ // 任务初始化
587
+ const init = async () => {
588
+ // 1. 从数据库读取任务列表
589
+ db = await database.init();
590
+ // 2. 创建 Bree 实例(在数据库初始化之后)
591
+ bree = createBree();
592
+ // 3. 从数据库读取任务列表
593
+ const jobs = await db('Sys_BreeJobs'); //.where('Status', 1)
594
+ // 4. 批量注册到调度器
595
+ for (const job of jobs) {
596
+ const id = job['ID'];
597
+ const name = job['Name'];
598
+ const cron = job['Cron'];
599
+ const path = job['Path'];
600
+ const status = job['Status']; // status 状态为0:已停止 1:执行中 2:
601
+
602
+ try {
603
+ await create({
604
+ name,
605
+ cron,
606
+ path: path || undefined,
607
+ worker: { workerData: { id } }
608
+ });
609
+
610
+ if (status === 1) await bree.start(name);
611
+ }
612
+ catch (error) {
613
+ blogger.error(name, error);
614
+ await db('Sys_BreeJobs')
615
+ .where('ID', id)
616
+ .update({
617
+ 'ResultStatus': 1,
618
+ 'ErrorMessage': error?.stack
619
+ });
620
+ }
621
+ }
622
+ };
623
+
624
+ var scheduler = {
625
+ init,
626
+ create,
627
+ reset,
628
+ start,
629
+ stop,
630
+ run,
631
+ getBree,
632
+ remove
633
+ };
634
+
635
+ const { combine: combine$1, timestamp: timestamp$1, printf: printf$1 } = winston.format;
636
+ const logFormat$1 = printf$1(({ timestamp, level, message }) => {
637
+ return `[${timestamp}] [${level.toUpperCase()}] ${message}`
638
+ });
639
+
640
+ /**
641
+ * 日志级别过滤器
642
+ */
643
+ const levelFilter = (level) => {
644
+ return winston.format((info) => {
645
+ return info.level === level ? info : false
646
+ })()
647
+ };
648
+
649
+ const logger = winston.createLogger({
650
+ level: 'info',
651
+ format: combine$1(
652
+ timestamp$1({ format: 'YYYY-MM-DD HH:mm:ss' }),
653
+ logFormat$1
654
+ ),
655
+ transports: [
656
+ new winston.transports.Console(),
657
+ new winston.transports.DailyRotateFile({
658
+ dirname: 'logs',
659
+ filename: 'info-%DATE%.log',
660
+ datePattern: 'YYYY-MM-DD',
661
+ maxSize: '20m',
662
+ maxFiles: '30d',
663
+ format: combine$1(
664
+ levelFilter('info'),
665
+ timestamp$1({ format: 'YYYY-MM-DD HH:mm:ss' }),
666
+ logFormat$1
667
+ )
668
+ }),
669
+ new winston.transports.DailyRotateFile({
670
+ dirname: 'logs',
671
+ filename: 'error-%DATE%.log',
672
+ level: 'error',
673
+ datePattern: 'YYYY-MM-DD',
674
+ maxSize: '20m',
675
+ maxFiles: '30d',
676
+ format: combine$1(
677
+ levelFilter('error'),
678
+ timestamp$1({ format: 'YYYY-MM-DD HH:mm:ss' }),
679
+ logFormat$1
680
+ )
681
+ })
682
+ ]
683
+ });
684
+
685
+ function useHandler() {
686
+ let isCancelled = false;
687
+ let db = null;
688
+
689
+ const getIsCancelled = () => isCancelled;
690
+ const updateTask = async (obj) => {
691
+ await db('Sys_BreeJobs')
692
+ .where('ID', workerData.id)
693
+ .update(obj);
694
+ };
695
+ const run = async (worker) => {
696
+ if (parentPort)
697
+ parentPort.once('message', (message) => {
698
+ console.log(message);
699
+ if (message === 'cancel') isCancelled = true;
700
+ });
701
+
702
+ db = await database.init();
703
+
704
+ try {
705
+ await worker({ logger, redis, db });
706
+ await updateTask({ 'ResultStatus': 0 });
707
+ } catch (err) {
708
+ await updateTask({ 'ResultStatus': 1, 'ErrorMessage': err.message });
709
+ logger.error(`${err?.stack || err?.message || err}`);
710
+ } finally {
711
+ await redis.close();
712
+ await database.close(); // 关闭连接池
713
+ if (parentPort) {
714
+ parentPort.postMessage("done");
715
+ } else {
716
+ process.exit(0);
717
+ }
718
+ }
719
+ };
720
+
721
+ return { run, getIsCancelled }
722
+ }
723
+
724
+ const ALGORITHM_MAP = {
725
+ 16: 'aes-128-ecb',
726
+ 24: 'aes-192-ecb',
727
+ 32: 'aes-256-ecb'
728
+ };
729
+
730
+ const encrypt = (data, key) => {
731
+ // key 必须 16 / 24 / 32 字节
732
+ const keyBuf = Buffer.from(key, 'utf8');
733
+ const cipher = crypto.createCipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null);
734
+ cipher.setAutoPadding(true); // PKCS7
735
+ const encrypted = Buffer.concat([
736
+ cipher.update(data),
737
+ cipher.final()
738
+ ]);
739
+ return encrypted
740
+ };
741
+
742
+ const decrypt = (data, key) => {
743
+ const keyBuf = Buffer.from(key, 'utf8');
744
+ const decipher = crypto.createDecipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null);
745
+ decipher.setAutoPadding(true);
746
+ const decrypted = Buffer.concat([
747
+ decipher.update(data),
748
+ decipher.final()
749
+ ]);
750
+ return decrypted
751
+ };
752
+
753
+ /**
754
+ * AES解密
755
+ * 对应 Java:
756
+ * AesUtil.decrypt(String data, String key)
757
+ *
758
+ * @param {string} data Base64密文
759
+ * @param {string} key AES密钥(16/24/32字节)
760
+ * @returns {string} 明文
761
+ */
762
+ const decryptString = (data, key) => {
763
+ const keyBuf = Buffer.from(key, 'utf8');
764
+ const decipher = crypto.createDecipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null);
765
+ decipher.setAutoPadding(true);
766
+ const decrypted = Buffer.concat([
767
+ decipher.update(Buffer.from(data, 'base64')),
768
+ decipher.final()
769
+ ]);
770
+ return decrypted.toString('utf8')
771
+ };
772
+
773
+ var aes = { encrypt, decrypt, decryptString };
774
+
775
+ function auth(req, res, next) {
776
+ const apiKey = req.headers['x-api-key'];
777
+
778
+ if (!apiKey) {
779
+ return res.status(200).json({
780
+ code: -1,
781
+ message: 'Missing API Key'
782
+ })
783
+ }
784
+
785
+ const decryptedApiKey = aes.decryptString(apiKey, process.env.API_SECRET_KEY);
786
+ if (!decryptedApiKey || decryptedApiKey !== process.env.API_TOKEN) {
787
+ return res.status(200).json({
788
+ code: -1,
789
+ message: 'Unauthorized'
790
+ })
791
+ }
792
+
793
+ let ip = req.ip;
794
+ console.log('Request IP:', ip);
795
+ if (ip.startsWith('::ffff:')) {
796
+ ip = ip.substring(7);
797
+ }
798
+
799
+ const allowIps = process.env.ALLOW_IPS?.split(',') || [];
800
+ if (!allowIps.includes(ip)) {
801
+ return res.status(200)
802
+ .json({
803
+ code: -1,
804
+ message: 'IP forbidden'
805
+ })
806
+ }
807
+
808
+ next();
809
+ }
810
+
811
+ const { combine, timestamp, printf } = winston.format;
812
+ const logFormat = printf(({ timestamp, level, message }) => {
813
+ return `[${timestamp}] [${level.toUpperCase()}] ${message}`
814
+ });
815
+
816
+ const weixinLogger = winston.createLogger({
817
+ level: 'info',
818
+ format: combine(
819
+ timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
820
+ logFormat
821
+ ),
822
+ transports: [
823
+ new winston.transports.Console(),
824
+ new winston.transports.DailyRotateFile({
825
+ dirname: 'logs',
826
+ filename: 'weixinapi-%DATE%.log',
827
+ datePattern: 'YYYY-MM-DD',
828
+ maxSize: '20m',
829
+ maxFiles: '30d'
830
+ })
831
+ ]
832
+ });
833
+
834
+ /**
835
+ * worker日志
836
+ */
837
+ const info = (apiName, message) => {
838
+ weixinLogger.info(`[${apiName}] ${message}`);
839
+ };
840
+
841
+ /**
842
+ * error日志
843
+ */
844
+ const error = (apiName, err) => {
845
+ weixinLogger.error(`[${apiName}] ${err?.stack || err?.message || err}`);
846
+ };
847
+ var weixinLogger_default = { info, error };
848
+
849
+ export { aes$1 as aes, auth, database as db, excelUtil as excel, mailUtil as mail, redis, scheduler, useHandler, weixinLogger_default as weixinLogger };
850
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/utils/aesUtil.js","../src/core/database.js","../src/utils/excelUtil.js","../src/utils/mailUtil.js","../src/core/redis.js","../src/utils/redisUtil.js","../src/utils/path.js","../src/config/breeLogger.js","../src/scheduler.js","../src/config/logger.js","../src/useHandler.js","../src/utils/AesUtil.js","../src/core/auth.js","../src/config/weixinLogger.js"],"sourcesContent":["import crypto from 'node:crypto'\r\n\r\nconst ALGORITHM_MAP = {\r\n 16: 'aes-128-ecb',\r\n 24: 'aes-192-ecb',\r\n 32: 'aes-256-ecb'\r\n}\r\n\r\nconst encrypt = (data, key) => {\r\n // key 必须 16 / 24 / 32 字节\r\n const keyBuf = Buffer.from(key, 'utf8')\r\n const cipher = crypto.createCipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null)\r\n cipher.setAutoPadding(true) // PKCS7\r\n const encrypted = Buffer.concat([\r\n cipher.update(data),\r\n cipher.final()\r\n ])\r\n return encrypted\r\n}\r\n\r\nconst decrypt = (data, key) => {\r\n const keyBuf = Buffer.from(key, 'utf8')\r\n const decipher = crypto.createDecipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null)\r\n decipher.setAutoPadding(true)\r\n const decrypted = Buffer.concat([\r\n decipher.update(data),\r\n decipher.final()\r\n ])\r\n return decrypted\r\n}\r\n\r\n/**\r\n * AES解密\r\n * 对应 Java:\r\n * AesUtil.decrypt(String data, String key)\r\n *\r\n * @param {string} data Base64密文\r\n * @param {string} key AES密钥(16/24/32字节)\r\n * @returns {string} 明文\r\n */\r\nconst decryptString = (data, key) => {\r\n const keyBuf = Buffer.from(key, 'utf8')\r\n const decipher = crypto.createDecipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null)\r\n decipher.setAutoPadding(true)\r\n const decrypted = Buffer.concat([\r\n decipher.update(Buffer.from(data, 'base64')),\r\n decipher.final()\r\n ])\r\n return decrypted.toString('utf8')\r\n}\r\n\r\nexport default { encrypt, decrypt, decryptString }","import knex from 'knex'\r\nimport dotenv from 'dotenv'\r\nimport aes from '../utils/aesUtil.js'\r\ndotenv.config()\r\n\r\nlet db = null\r\nconst init = async () => {\r\n const connectionString = process.env.DB_CONNECTION_STRING\r\n const aesKey = process.env.DB_AES_KEY\r\n try {\r\n const decryptedConnectionString = aes.decryptString(connectionString, aesKey)\r\n const connectionParams = decryptedConnectionString.split(';').reduce((acc, param) => {\r\n const [key, value] = param.split('=')\r\n acc[key] = value\r\n return acc\r\n }, {})\r\n db = knex({\r\n client: 'mssql',\r\n connection: {\r\n user: connectionParams.user,\r\n password: connectionParams.password,\r\n server: connectionParams.server,\r\n database: connectionParams.database,\r\n options: {\r\n encrypt: false\r\n }\r\n }\r\n })\r\n\r\n // 等待数据库真实连接\r\n await db.raw('SELECT 1')\r\n console.log('database initialized')\r\n return db\r\n } catch (error) {\r\n await close()\r\n\r\n throw error\r\n }\r\n}\r\n\r\nconst close = async () => {\r\n if (db) {\r\n await db.destroy()\r\n db = null\r\n }\r\n}\r\n\r\nexport default {\r\n init,\r\n close\r\n}","import ExcelJS from 'exceljs'\r\nimport path from 'node:path'\r\n\r\n/**\r\n * 内部:构建 sheet columns:[{ header: 'ID', key: 'id', width: 10 }]\r\n */\r\nconst buildSheet = (workbook, columns, data) => {\r\n const sheet = workbook.addWorksheet('sheet1')\r\n sheet.columns = columns\r\n for (const item of data) {\r\n sheet.addRow(item)\r\n }\r\n return sheet\r\n}\r\n\r\n/**\r\n * 小/中数据:生成 Excel 文件(落盘)\r\n * 适合:< 5w 行\r\n */\r\nconst createExcel = async (columns, data, fileName = 'report') => {\r\n const workbook = new ExcelJS.Workbook()\r\n buildSheet(workbook, columns, data)\r\n const filePath = path.join(process.cwd(), `${fileName}.xlsx`)\r\n await workbook.xlsx.writeFile(filePath)\r\n return filePath\r\n}\r\n\r\n/**\r\n * 邮件专用:生成 Buffer(不落盘)\r\n * 适合:中小数据\r\n */\r\nconst createBufferExcel = async (columns, data) => {\r\n const workbook = new ExcelJS.Workbook()\r\n buildSheet(workbook, columns, data)\r\n return await workbook.xlsx.writeBuffer()\r\n}\r\n\r\n/**\r\n * 大数据(核心优化):流式写入(不爆内存)\r\n * 适合:10w ~ 100w+\r\n */\r\nconst createStreamExcel = async (columns, data, fileName = 'report') => {\r\n const filePath = path.join(process.cwd(), `${fileName}.xlsx`)\r\n const workbook = new ExcelJS.stream.xlsx.WorkbookWriter({\r\n filename: filePath,\r\n useStyles: false,\r\n useSharedStrings: true\r\n })\r\n\r\n const sheet = workbook.addWorksheet('Report')\r\n sheet.columns = columns\r\n for (const item of data) {\r\n sheet.addRow(item).commit()\r\n }\r\n await workbook.commit()\r\n return filePath\r\n}\r\n\r\n/**\r\n * 🚀 统一入口(推荐用这个)\r\n */\r\nconst exportExcel = async ({\r\n mode = 'file', // file | buffer | stream\r\n columns,\r\n data,\r\n fileName = 'report'\r\n}) => {\r\n switch (mode) {\r\n case 'buffer':\r\n return await createBufferExcel(columns, data)\r\n\r\n case 'stream':\r\n return await createStreamExcel(columns, data, fileName)\r\n\r\n default:\r\n return await createExcel(columns, data, fileName)\r\n }\r\n}\r\n\r\nexport default {\r\n exportExcel,\r\n createExcel,\r\n createBufferExcel,\r\n createStreamExcel\r\n}","import nodemailer from 'nodemailer'\r\nimport path from 'node:path'\r\n\r\nlet transporter = null\r\nlet from = ''\r\nconst init = () => {\r\n from = `\"${process.env.MAIL_USERNAME}\" <${process.env.MAIL_ACCOUNT}>`\r\n transporter = nodemailer.createTransport({\r\n host: process.env.MAIL_HOST, // 或公司邮箱 SMTP\r\n port: Number(process.env.MAIL_PORT),\r\n secure: true,\r\n auth: {\r\n user: process.env.MAIL_ACCOUNT,\r\n pass: process.env.MAIL_PASSWORD // 注意不是密码\r\n }\r\n })\r\n}\r\n\r\nconst send = async (subject, toUser = '', copyUser = '', content = '', filePath = []) => {\r\n await transporter.sendMail({\r\n from: from,\r\n to: toUser.split(',').map(i => i.trim()).filter(Boolean),\r\n cc: copyUser.split(',').map(i => i.trim()).filter(Boolean),\r\n subject: subject,\r\n text: content,\r\n attachments: filePath.map(file => {\r\n const filename = path.basename(file) // ⭐ 核心:自动截取文件名\r\n return {\r\n path: file,\r\n filename\r\n }\r\n })\r\n })\r\n}\r\n\r\nexport default {\r\n init,\r\n send\r\n}","import { createClient } from 'redis'\r\n\r\nlet client = null\r\nlet isConnected = false\r\n\r\nasync function createRedisClient() {\r\n const redis = createClient({\r\n socket: {\r\n host: process.env.REDIS_HOST,\r\n port: Number(process.env.REDIS_PORT),\r\n reconnectStrategy(retries) {\r\n console.log(`Redis 重连 ${retries}`)\r\n\r\n // 超过 2 次停止重连\r\n if (retries > 3) {\r\n return new Error('Redis 重连失败')\r\n }\r\n\r\n return Math.min(retries * 1000, 5000)\r\n }\r\n },\r\n RESP: 2, // ⭐关键\r\n username: process.env.REDIS_USERNAME || undefined,\r\n password: process.env.REDIS_PASSWORD || undefined,\r\n database: Number(process.env.REDIS_DB || 0)\r\n })\r\n\r\n redis.on('connect', () => {\r\n console.log('Redis 正在连接...')\r\n })\r\n\r\n redis.on('ready', () => {\r\n isConnected = true\r\n console.log('Redis 已连接')\r\n })\r\n\r\n redis.on('reconnecting', () => {\r\n console.log('Redis 重连中...')\r\n })\r\n\r\n redis.on('end', () => {\r\n isConnected = false\r\n console.log('Redis 已断开')\r\n })\r\n\r\n redis.on('error', (err) => {\r\n console.error('Redis异常:', err.message)\r\n })\r\n\r\n await redis.connect()\r\n\r\n return redis\r\n}\r\n\r\nexport async function getRedis() {\r\n if (!client) {\r\n client = await createRedisClient()\r\n }\r\n\r\n return client\r\n}\r\n\r\nexport function redisConnected() {\r\n return isConnected\r\n}\r\n\r\nexport async function closeRedis() {\r\n if (client) {\r\n await client.quit()\r\n client = null\r\n }\r\n}","import { getRedis, closeRedis } from '../core/redis.js'\r\n\r\nclass RedisHelper {\r\n async set(key, value, expireSeconds = null) {\r\n const redis = await getRedis()\r\n\r\n const data =\r\n typeof value === 'object'\r\n ? JSON.stringify(value)\r\n : String(value)\r\n\r\n if (expireSeconds) {\r\n return await redis.set(key, data, {\r\n EX: expireSeconds\r\n })\r\n }\r\n\r\n return await redis.set(key, data)\r\n }\r\n\r\n async get(key) {\r\n const redis = await getRedis()\r\n\r\n const value = await redis.get(key)\r\n\r\n if (!value) return null\r\n\r\n try {\r\n return JSON.parse(value)\r\n } catch {\r\n return value\r\n }\r\n }\r\n\r\n async del(key) {\r\n const redis = await getRedis()\r\n return await redis.del(key)\r\n }\r\n\r\n async exists(key) {\r\n const redis = await getRedis()\r\n return (await redis.exists(key)) === 1\r\n }\r\n\r\n async expire(key, seconds) {\r\n const redis = await getRedis()\r\n return await redis.expire(key, seconds)\r\n }\r\n\r\n async ttl(key) {\r\n const redis = await getRedis()\r\n return await redis.ttl(key)\r\n }\r\n\r\n async incr(key) {\r\n const redis = await getRedis()\r\n return await redis.incr(key)\r\n }\r\n\r\n async decr(key) {\r\n const redis = await getRedis()\r\n return await redis.decr(key)\r\n }\r\n\r\n async hSet(key, field, value) {\r\n const redis = await getRedis()\r\n\r\n return await redis.hSet(\r\n key,\r\n field,\r\n typeof value === 'object'\r\n ? JSON.stringify(value)\r\n : String(value)\r\n )\r\n }\r\n\r\n async hGet(key, field) {\r\n const redis = await getRedis()\r\n\r\n const value = await redis.hGet(key, field)\r\n\r\n if (!value) return null\r\n\r\n try {\r\n return JSON.parse(value)\r\n } catch {\r\n return value\r\n }\r\n }\r\n\r\n async hGetAll(key) {\r\n const redis = await getRedis()\r\n return await redis.hGetAll(key)\r\n }\r\n\r\n async lPush(key, value) {\r\n const redis = await getRedis()\r\n\r\n return await redis.lPush(\r\n key,\r\n JSON.stringify(value)\r\n )\r\n }\r\n\r\n async rPop(key) {\r\n const redis = await getRedis()\r\n\r\n const value = await redis.rPop(key)\r\n\r\n return value\r\n ? JSON.parse(value)\r\n : null\r\n }\r\n\r\n async close() {\r\n await closeRedis()\r\n }\r\n}\r\n\r\nexport default new RedisHelper()","import path from 'node:path'\r\nimport { fileURLToPath } from 'node:url'\r\n\r\nconst __filename = fileURLToPath(import.meta.url)\r\nconst __dirname = path.dirname(__filename)\r\n\r\nexport { __filename, __dirname }","import winston from 'winston'\r\nimport 'winston-daily-rotate-file'\r\n\r\nconst { combine, timestamp, printf } = winston.format\r\nconst logFormat = printf(({ timestamp, level, message }) => {\r\n return `[${timestamp}] [${level.toUpperCase()}] ${message}`\r\n})\r\n\r\nconst breeLogger = winston.createLogger({\r\n level: 'info',\r\n format: combine(\r\n timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\r\n logFormat\r\n ),\r\n transports: [\r\n new winston.transports.Console(),\r\n new winston.transports.DailyRotateFile({\r\n dirname: 'logs',\r\n filename: 'worker-%DATE%.log',\r\n datePattern: 'YYYY-MM-DD',\r\n maxSize: '20m',\r\n maxFiles: '30d'\r\n })\r\n ]\r\n})\r\n\r\n/**\r\n * worker日志\r\n */\r\nconst worker = (jobName, message) => {\r\n breeLogger.info(`[${jobName}] ${message}`)\r\n}\r\n\r\n/**\r\n * error日志\r\n */\r\nconst error = (jobName, err) => {\r\n breeLogger.error(`[${jobName}] ${err?.stack || err?.message || err}`)\r\n}\r\n\r\nexport { worker, error }\r\nexport default { worker, error }","import Bree from 'bree'\r\nimport path from 'node:path'\r\nimport fs from 'node:fs'\r\nimport { __dirname } from './utils/path.js'\r\nimport blogger from './config/breeLogger.js'\r\nimport database from './core/database.js'\r\n\r\nconst projectRoot = path.resolve(__dirname, '../../')\r\n\r\nlet bree = null\r\nlet db = null\r\nlet jobsRoot = null\r\n\r\n// 让使用者通过环境变量或配置指定 jobs 目录\r\nconst getJobsRoot = () => {\r\n if (jobsRoot) return jobsRoot\r\n\r\n // 多种方式获取 jobs 目录\r\n // 1. 环境变量\r\n if (process.env.BREE_JOBS_PATH) {\r\n jobsRoot = path.resolve(process.env.BREE_JOBS_PATH)\r\n return jobsRoot\r\n }\r\n\r\n // 2. 使用当前工作目录(项目根目录)\r\n const cwd = process.cwd()\r\n const possiblePaths = [\r\n path.join(cwd, 'src/jobs'),\r\n path.join(cwd, 'jobs'),\r\n path.join(cwd, 'dist/jobs'),\r\n ]\r\n\r\n for (const p of possiblePaths) {\r\n if (fs.existsSync(p)) {\r\n jobsRoot = p\r\n return jobsRoot\r\n }\r\n }\r\n\r\n // 3. 默认使用当前工作目录下的 src/jobs\r\n jobsRoot = path.join(cwd, 'src/jobs')\r\n console.warn(`Jobs directory not found, using default: ${jobsRoot}`)\r\n return jobsRoot\r\n}\r\n\r\nconst createBree = () => {\r\n const jobsPath = getJobsRoot()\r\n // 确保 jobs 目录存在(创建警告但不自动创建,因为这是使用者的责任)\r\n if (!fs.existsSync(jobsPath)) {\r\n console.warn(`⚠️ Jobs directory not found: ${jobsPath}`)\r\n console.warn(` Please create it or set BREE_JOBS_PATH environment variable`)\r\n }\r\n const instance = new Bree({\r\n hasSeconds: true,\r\n root: jobsPath,\r\n errorHandler: async (error, workerMetadata) => {\r\n if (workerMetadata?.threadId) {\r\n blogger.worker(workerMetadata.name,\r\n `There was an error while running a worker ${workerMetadata.name} with thread ID: ${workerMetadata.threadId}`)\r\n } else {\r\n blogger.worker(workerMetadata.name,\r\n `There was an error while running a worker ${workerMetadata.name}`)\r\n }\r\n\r\n blogger.error(workerMetadata?.name, error)\r\n if (error?.message?.indexOf('exited with code') > -1) return\r\n const job = instance.config.jobs.find(x => x.name === workerMetadata?.name)\r\n const workerData = job?.worker?.workerData\r\n if (workerData) {\r\n await db('Sys_BreeJobs')\r\n .where('ID', workerData.id)\r\n .update({\r\n 'ResultStatus': 1,\r\n 'ErrorMessage': error?.stack\r\n })\r\n }\r\n }\r\n })\r\n\r\n instance.on('worker created', (name) => {\r\n console.log('worker created', name)\r\n blogger.worker(name, 'worker created')\r\n })\r\n\r\n instance.on('worker deleted', (name) => {\r\n console.log('worker deleted', name)\r\n blogger.worker(name, 'worker deleted')\r\n })\r\n\r\n return instance\r\n}\r\n\r\nconst getBree = () => {\r\n return bree\r\n}\r\n\r\nconst reset = async (job, startStatus) => {\r\n await bree.stop(job.name)\r\n const index = bree.config.jobs.findIndex(x => x.name === job.name)\r\n if (index !== -1) bree.config.jobs.splice(index, 1)\r\n await bree.add(job)\r\n if (startStatus) await bree.start(job.name)\r\n}\r\n\r\nconst remove = async (name) => {\r\n await bree.stop(name)\r\n\r\n // 删除运行中的 worker 貌似不需要\r\n // delete bree.workers.get(name)\r\n\r\n const index = bree.config.jobs.findIndex(x => x.name === name)\r\n if (index !== -1) bree.config.jobs.splice(index, 1)\r\n}\r\n\r\nconst create = async (job) => {\r\n if (bree.config.jobs.some(x => x.name === job.name))\r\n return\r\n\r\n await bree.add(job)\r\n}\r\n\r\n// 启动任务\r\nconst start = async (name) => {\r\n await bree.start(name)\r\n}\r\n// 停止任务\r\nconst stop = async (name) => {\r\n await bree.stop(name)\r\n}\r\n// 执行一次任务\r\nconst run = async (name) => {\r\n await bree.run(name)\r\n}\r\n\r\n// 任务初始化\r\nconst init = async () => {\r\n // 1. 从数据库读取任务列表\r\n db = await database.init()\r\n // 2. 创建 Bree 实例(在数据库初始化之后)\r\n bree = createBree()\r\n // 3. 从数据库读取任务列表\r\n const jobs = await db('Sys_BreeJobs') //.where('Status', 1)\r\n // 4. 批量注册到调度器\r\n for (const job of jobs) {\r\n const id = job['ID']\r\n const name = job['Name']\r\n const cron = job['Cron']\r\n const path = job['Path']\r\n const status = job['Status'] // status 状态为0:已停止 1:执行中 2:\r\n\r\n try {\r\n await create({\r\n name,\r\n cron,\r\n path: path || undefined,\r\n worker: { workerData: { id } }\r\n })\r\n\r\n if (status === 1) await bree.start(name)\r\n }\r\n catch (error) {\r\n blogger.error(name, error)\r\n await db('Sys_BreeJobs')\r\n .where('ID', id)\r\n .update({\r\n 'ResultStatus': 1,\r\n 'ErrorMessage': error?.stack\r\n })\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n init,\r\n create,\r\n reset,\r\n start,\r\n stop,\r\n run,\r\n getBree,\r\n remove\r\n}","import winston from 'winston'\r\nimport 'winston-daily-rotate-file'\r\n\r\nconst { combine, timestamp, printf } = winston.format\r\nconst logFormat = printf(({ timestamp, level, message }) => {\r\n return `[${timestamp}] [${level.toUpperCase()}] ${message}`\r\n})\r\n\r\n/**\r\n * 日志级别过滤器\r\n */\r\nconst levelFilter = (level) => {\r\n return winston.format((info) => {\r\n return info.level === level ? info : false\r\n })()\r\n}\r\n\r\nconst logger = winston.createLogger({\r\n level: 'info',\r\n format: combine(\r\n timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\r\n logFormat\r\n ),\r\n transports: [\r\n new winston.transports.Console(),\r\n new winston.transports.DailyRotateFile({\r\n dirname: 'logs',\r\n filename: 'info-%DATE%.log',\r\n datePattern: 'YYYY-MM-DD',\r\n maxSize: '20m',\r\n maxFiles: '30d',\r\n format: combine(\r\n levelFilter('info'),\r\n timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\r\n logFormat\r\n )\r\n }),\r\n new winston.transports.DailyRotateFile({\r\n dirname: 'logs',\r\n filename: 'error-%DATE%.log',\r\n level: 'error',\r\n datePattern: 'YYYY-MM-DD',\r\n maxSize: '20m',\r\n maxFiles: '30d',\r\n format: combine(\r\n levelFilter('error'),\r\n timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\r\n logFormat\r\n )\r\n })\r\n ]\r\n})\r\n\r\nexport default logger","import { parentPort, workerData } from 'node:worker_threads'\r\nimport logger from './config/logger.js'\r\nimport redis from './utils/redisUtil.js'\r\nimport database from './core/database.js'\r\n\r\nexport function useHandler() {\r\n let isCancelled = false\r\n let db = null\r\n\r\n const getIsCancelled = () => isCancelled\r\n const updateTask = async (obj) => {\r\n await db('Sys_BreeJobs')\r\n .where('ID', workerData.id)\r\n .update(obj)\r\n }\r\n const run = async (worker) => {\r\n if (parentPort)\r\n parentPort.once('message', (message) => {\r\n console.log(message)\r\n if (message === 'cancel') isCancelled = true\r\n })\r\n\r\n db = await database.init()\r\n\r\n try {\r\n await worker({ logger, redis, db })\r\n await updateTask({ 'ResultStatus': 0 })\r\n } catch (err) {\r\n await updateTask({ 'ResultStatus': 1, 'ErrorMessage': err.message })\r\n logger.error(`${err?.stack || err?.message || err}`)\r\n } finally {\r\n await redis.close()\r\n await database.close() // 关闭连接池\r\n if (parentPort) {\r\n parentPort.postMessage(\"done\")\r\n } else {\r\n process.exit(0)\r\n }\r\n }\r\n }\r\n\r\n return { run, getIsCancelled }\r\n}\r\n","import crypto from 'node:crypto'\r\n\r\nconst ALGORITHM_MAP = {\r\n 16: 'aes-128-ecb',\r\n 24: 'aes-192-ecb',\r\n 32: 'aes-256-ecb'\r\n}\r\n\r\nconst encrypt = (data, key) => {\r\n // key 必须 16 / 24 / 32 字节\r\n const keyBuf = Buffer.from(key, 'utf8')\r\n const cipher = crypto.createCipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null)\r\n cipher.setAutoPadding(true) // PKCS7\r\n const encrypted = Buffer.concat([\r\n cipher.update(data),\r\n cipher.final()\r\n ])\r\n return encrypted\r\n}\r\n\r\nconst decrypt = (data, key) => {\r\n const keyBuf = Buffer.from(key, 'utf8')\r\n const decipher = crypto.createDecipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null)\r\n decipher.setAutoPadding(true)\r\n const decrypted = Buffer.concat([\r\n decipher.update(data),\r\n decipher.final()\r\n ])\r\n return decrypted\r\n}\r\n\r\n/**\r\n * AES解密\r\n * 对应 Java:\r\n * AesUtil.decrypt(String data, String key)\r\n *\r\n * @param {string} data Base64密文\r\n * @param {string} key AES密钥(16/24/32字节)\r\n * @returns {string} 明文\r\n */\r\nconst decryptString = (data, key) => {\r\n const keyBuf = Buffer.from(key, 'utf8')\r\n const decipher = crypto.createDecipheriv(ALGORITHM_MAP[keyBuf.length], keyBuf, null)\r\n decipher.setAutoPadding(true)\r\n const decrypted = Buffer.concat([\r\n decipher.update(Buffer.from(data, 'base64')),\r\n decipher.final()\r\n ])\r\n return decrypted.toString('utf8')\r\n}\r\n\r\nexport default { encrypt, decrypt, decryptString }","import aes from \"../utils/AesUtil.js\"\r\n\r\nexport function auth(req, res, next) {\r\n const apiKey = req.headers['x-api-key']\r\n\r\n if (!apiKey) {\r\n return res.status(200).json({\r\n code: -1,\r\n message: 'Missing API Key'\r\n })\r\n }\r\n\r\n const decryptedApiKey = aes.decryptString(apiKey, process.env.API_SECRET_KEY)\r\n if (!decryptedApiKey || decryptedApiKey !== process.env.API_TOKEN) {\r\n return res.status(200).json({\r\n code: -1,\r\n message: 'Unauthorized'\r\n })\r\n }\r\n\r\n let ip = req.ip\r\n console.log('Request IP:', ip)\r\n if (ip.startsWith('::ffff:')) {\r\n ip = ip.substring(7)\r\n }\r\n\r\n const allowIps = process.env.ALLOW_IPS?.split(',') || []\r\n if (!allowIps.includes(ip)) {\r\n return res.status(200)\r\n .json({\r\n code: -1,\r\n message: 'IP forbidden'\r\n })\r\n }\r\n\r\n next()\r\n}","import winston from 'winston'\r\nimport 'winston-daily-rotate-file'\r\n\r\nconst { combine, timestamp, printf } = winston.format\r\nconst logFormat = printf(({ timestamp, level, message }) => {\r\n return `[${timestamp}] [${level.toUpperCase()}] ${message}`\r\n})\r\n\r\nconst weixinLogger = winston.createLogger({\r\n level: 'info',\r\n format: combine(\r\n timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),\r\n logFormat\r\n ),\r\n transports: [\r\n new winston.transports.Console(),\r\n new winston.transports.DailyRotateFile({\r\n dirname: 'logs',\r\n filename: 'weixinapi-%DATE%.log',\r\n datePattern: 'YYYY-MM-DD',\r\n maxSize: '20m',\r\n maxFiles: '30d'\r\n })\r\n ]\r\n})\r\n\r\n/**\r\n * worker日志\r\n */\r\nconst info = (apiName, message) => {\r\n weixinLogger.info(`[${apiName}] ${message}`)\r\n}\r\n\r\n/**\r\n * error日志\r\n */\r\nconst error = (apiName, err) => {\r\n weixinLogger.error(`[${apiName}] ${err?.stack || err?.message || err}`)\r\n}\r\n\r\nexport { info, error }\r\nexport default { info, error }"],"names":["ALGORITHM_MAP","encrypt","decrypt","decryptString","db","init","aes","__filename","__dirname","combine","timestamp","printf","logFormat","error"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "name": "@layoutkit/bree-core",
3
+ "version": "1.0.6",
4
+ "description": "Reusable Bree scheduler core package",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "exports": {
8
+ ".": "./dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "rollup -c"
15
+ },
16
+ "dependencies": {
17
+ "bree": "^9.2.9",
18
+ "crypto": "^1.0.1",
19
+ "dotenv": "^17.4.2",
20
+ "exceljs": "^4.4.0",
21
+ "knex": "^3.3.0",
22
+ "mssql": "^12.7.0",
23
+ "nodemailer": "^9.0.5",
24
+ "redis": "^6.2.0",
25
+ "winston": "^3.19.0",
26
+ "winston-daily-rotate-file": "^5.0.0"
27
+ },
28
+ "devDependencies": {
29
+ "@rollup/plugin-commonjs": "^29.0.3",
30
+ "@rollup/plugin-node-resolve": "^16.0.3",
31
+ "rollup": "^4.62.4"
32
+ }
33
+ }