/* * @Author: renxia * @Date: 2024-02-20 10:31:21 * @LastEditors: renxia * @LastEditTime: 2024-04-08 11:18:27 * @Description: */ import { type AnyObject, Request } from '@lzwme/fe-utils'; import { strip, redBright } from 'console-log-colors'; import { getCacheStorage, sendNotify } from './common'; interface EnvOptions { /** 多账号分隔符。默认为 &、\n */ sep?: string[]; /** 是否开启消息通知。默认为 true */ notifyFlag?: boolean; } export class Env { public index = 0; private startTime = Date.now(); private msgs: string[] = []; private options: EnvOptions = { sep: ['&', '\n'], }; public hasError: boolean | number = 0; public req = new Request(undefined, { 'content-type': 'application/json' }); public storage: ReturnType>; constructor(public name: string, options?: EnvOptions) { this.log(`[${this.name}]开始运行\n`, 'debug'); this.storage = getCacheStorage(name); if (options) Object.assign(this.options, options); } public async init(Task?: any, envName?: string, envValue?: string) { await this.storage.ready(); if (Task) { if (!envValue && envName) envName.split('|').some((eName) => (envValue = process.env[eName])); if (envValue) { const users = this.parse(envValue, this.options.sep); await this.runTask(Task, users); } else { this.log(`环境变量 ${redBright(envName)} 未定义`, 'error'); } } return this; } public async runTask(Task: any, usersConfig: any[]) { try { for (let [idx, userConfig] of Object.entries(usersConfig)) { try { this.index = +idx + 1; let desc = ''; if (typeof userConfig === 'string') [userConfig, desc = ''] = userConfig.split('##'); // 支持以 ## 隔离描述,可主要用于唯一 uid 标记 this.log(`🆔账号${this.index}:${desc || ''}`); if (typeof Task.prototype?.start === 'function') { const t = new Task(userConfig, this.index, desc); await t.start(); } else await Task(userConfig, this.index, desc); } catch (error) { console.error(error); this.log(`❌账号 ${this.index} 运行异常:${(error as Error).message}`, 'error'); } } } catch (e) { const error = e as Error; console.error(error); this.log(`❌运行异常:${error.message}`, 'error'); } this.done(); } public parse(envValue: string, mutiAccountSeps = this.options.sep!) { if (!envValue) return []; const sep = mutiAccountSeps.find((d) => envValue.includes(d)) || mutiAccountSeps[0]; const arr = envValue.split(sep).filter(Boolean); if (arr.length > 1) this.log(`共找到了 ${arr.length} 个账号`); return arr; } public log(msg: string, type: 'error' | 'info' | 'warn' | 'log' | 'debug' | 'D' = 'info') { if (type === 'D') type = 'debug'; if (type === 'error') { this.hasError = true; if (!msg.startsWith('❌') && !/^[\ud800-\udbff][\udc00-\udfff]/.test(msg)) msg = `❌ ${msg}`; } if (type !== 'debug') this.msgs.push(strip(msg)); console[type](msg); } uuid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = (Math.random() * 16) | 0; return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16); }); } wait(delay: number, gap = 0, showTip = true) { if (gap > 0) delay += Math.floor(Math.random() * gap); if (showTip) this.log(`等待 ${delay}ms 后继续...`, 'debug'); return new Promise((rs) => setTimeout(rs, delay)); } public getMsgs() { return this.msgs.join('\n'); } private end = false; public async done() { if (this.end) return; this.end = true; if (this.options.notifyFlag !== false && this.msgs.length) { await sendNotify(this.name, this.getMsgs(), { hasError: this.hasError, isPrint: false, exit: false }); } this.log(`运行结束,共运行了 ${Math.ceil((Date.now() - this.startTime) / 1000)} 秒`); process.exit(this.hasError ? 1 : 0); } }