Upload 44 files
Browse files- Yunzai/.gitignore +0 -1
- Yunzai/.npmrc +3 -1
- Yunzai/CHANGELOG.md +16 -0
- Yunzai/README.md +19 -3
- Yunzai/lib/bot.js +157 -41
- Yunzai/lib/config/config.js +8 -6
- Yunzai/lib/config/init.js +25 -18
- Yunzai/lib/config/redis.js +1 -0
- Yunzai/lib/events/connect.js +2 -2
- Yunzai/lib/events/online.js +2 -2
- Yunzai/lib/modules/oicq/index.js +14 -13
- Yunzai/lib/plugins/loader.js +20 -20
- Yunzai/lib/plugins/plugin.js +9 -0
- Yunzai/lib/plugins/runtime.js +6 -3
- Yunzai/lib/plugins/stdin.js +12 -37
- Yunzai/lib/tools/log.js +34 -0
- Yunzai/package-lock.json +0 -0
- Yunzai/package.json +12 -13
- Yunzai/pnpm-lock.yaml +0 -0
Yunzai/.gitignore
CHANGED
@@ -137,7 +137,6 @@ config/test/*
|
|
137 |
data/
|
138 |
!config/test/default.yaml
|
139 |
logs/
|
140 |
-
resources/
|
141 |
|
142 |
# Docker file
|
143 |
redis
|
|
|
137 |
data/
|
138 |
!config/test/default.yaml
|
139 |
logs/
|
|
|
140 |
|
141 |
# Docker file
|
142 |
redis
|
Yunzai/.npmrc
CHANGED
@@ -1,3 +1,5 @@
|
|
1 |
registry=https://registry.npmmirror.com
|
2 |
node_sqlite3_binary_host_mirror=https://npmmirror.com/mirrors/sqlite3
|
3 |
-
canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas
|
|
|
|
|
|
1 |
registry=https://registry.npmmirror.com
|
2 |
node_sqlite3_binary_host_mirror=https://npmmirror.com/mirrors/sqlite3
|
3 |
+
canvas_binary_host_mirror=https://npmmirror.com/mirrors/canvas
|
4 |
+
sharp_binary_host=https://npmmirror.com/mirrors/sharp
|
5 |
+
sharp_libvips_binary_host=https://npmmirror.com/mirrors/sharp-libvips
|
Yunzai/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
# 3.1.1
|
2 |
|
3 |
* 支持协议端:米游社大别野Bot
|
|
|
1 |
+
# 3.1.3
|
2 |
+
|
3 |
+
* 支持协议端:QQBot
|
4 |
+
* **请注意:**
|
5 |
+
* 从3.1.3版本开始,原genshin包内的功能会逐步重构,与miao-plugin进行整合,以降低后续游戏版本升级时的维护成本
|
6 |
+
* 在整合过程中,可能会移除一些重复或迁移成本较高的功能,以及可能会有功能不稳定情况
|
7 |
+
* 如介意,请切换至**v312-backup**分支
|
8 |
+
|
9 |
+
# 3.1.2
|
10 |
+
|
11 |
+
* 支持协议端:OPQBot
|
12 |
+
* 新增`#绑定用户`命令
|
13 |
+
* 可将其他QQ绑定至当前用户,以打通多个用户,子用户使用主用户的CK与UID等信息
|
14 |
+
* 同时也可绑定其他平台的用户,例如频道、微信等。如需链接至其他平台需使用TRSS-Yunzai或Lain-plugin
|
15 |
+
* 部分命令可能无法识别绑定后的主用户,如遇问题可反馈
|
16 |
+
|
17 |
# 3.1.1
|
18 |
|
19 |
* 支持协议端:米游社大别野Bot
|
Yunzai/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
# TRSS-Yunzai
|
4 |
|
5 |
-
Yunzai 应用端,支持多账号,支持协议端:go-cqhttp、ComWeChat、GSUIDCore、ICQQ、QQ频道、微信、KOOK、Telegram、Discord
|
6 |
|
7 |
[](https://github.com/TimeRainStarSky/Yunzai)
|
8 |
[](../../stargazers)
|
@@ -118,6 +118,12 @@ ws://localhost:2536/GSUIDCore
|
|
118 |
|
119 |
</details>
|
120 |
|
|
|
|
|
|
|
|
|
|
|
|
|
121 |
<details><summary>QQ频道</summary>
|
122 |
|
123 |
[TRSS-Yunzai QQGuild Plugin](../../../Yunzai-QQGuild-Plugin)
|
@@ -154,9 +160,19 @@ ws://localhost:2536/GSUIDCore
|
|
154 |
|
155 |
</details>
|
156 |
|
157 |
-
<details><summary
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
|
159 |
-
[TRSS-Yunzai
|
160 |
|
161 |
</details>
|
162 |
|
|
|
2 |
|
3 |
# TRSS-Yunzai
|
4 |
|
5 |
+
Yunzai 应用端,支持多账号,支持协议端:go-cqhttp、ComWeChat、GSUIDCore、ICQQ、QQBot、QQ频道、微信、KOOK、Telegram、Discord、OPQBot
|
6 |
|
7 |
[](https://github.com/TimeRainStarSky/Yunzai)
|
8 |
[](../../stargazers)
|
|
|
118 |
|
119 |
</details>
|
120 |
|
121 |
+
<details><summary>QQBot</summary>
|
122 |
+
|
123 |
+
[TRSS-Yunzai QQBot Plugin](../../../Yunzai-QQBot-Plugin)
|
124 |
+
|
125 |
+
</details>
|
126 |
+
|
127 |
<details><summary>QQ频道</summary>
|
128 |
|
129 |
[TRSS-Yunzai QQGuild Plugin](../../../Yunzai-QQGuild-Plugin)
|
|
|
160 |
|
161 |
</details>
|
162 |
|
163 |
+
<details><summary>OPQBot</summary>
|
164 |
+
|
165 |
+
下载运行 [OPQBot](https://opqbot.com),启动参数添加:
|
166 |
+
|
167 |
+
```
|
168 |
+
-wsserver ws://localhost:2536/OPQBot
|
169 |
+
```
|
170 |
+
|
171 |
+
</details>
|
172 |
+
|
173 |
+
<details><summary>路由</summary>
|
174 |
|
175 |
+
[TRSS-Yunzai Route Plugin](../../../Yunzai-Route-Plugin)
|
176 |
|
177 |
</details>
|
178 |
|
Yunzai/lib/bot.js
CHANGED
@@ -7,48 +7,61 @@ import express from "express"
|
|
7 |
import http from "http"
|
8 |
import { WebSocketServer } from "ws"
|
9 |
import _ from "lodash"
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
export default class Yunzai extends EventEmitter {
|
12 |
constructor() {
|
13 |
super()
|
14 |
this.uin = []
|
15 |
this.adapter = []
|
|
|
16 |
this.express = express()
|
17 |
this.server = http.createServer(this.express)
|
18 |
-
|
19 |
-
|
20 |
-
conn.id = `${req.connection.remoteAddress}-${req.headers["sec-websocket-key"]}`
|
21 |
-
this.makeLog("mark", `${logger.blue(`[${conn.id} <=> ${req.url}]`)} 建立连接:${JSON.stringify(req.headers)}`)
|
22 |
-
conn.on("error", logger.error)
|
23 |
-
conn.on("close", () => this.makeLog("mark", `${logger.blue(`[${conn.id} <≠> ${req.url}]`)} 断开连接`))
|
24 |
-
conn.on("message", msg => this.makeLog("debug", `${logger.blue(`[${conn.id} => ${req.url}]`)} 消息:${String(msg).trim()}`))
|
25 |
-
conn.sendMsg = msg => {
|
26 |
-
if (typeof msg == "object")
|
27 |
-
msg = JSON.stringify(msg)
|
28 |
-
this.makeLog("debug", `${logger.blue(`[${conn.id} <= ${req.url}]`)} 消息:${msg}`)
|
29 |
-
return conn.send(msg)
|
30 |
-
}
|
31 |
-
for (const i of this.wsf[req.url.split("/")[1]] || [])
|
32 |
-
i(conn, req, socket, head)
|
33 |
-
})
|
34 |
-
})
|
35 |
this.wss = new WebSocketServer({ noServer: true })
|
36 |
this.wsf = {}
|
|
|
|
|
|
|
|
|
|
|
37 |
}
|
38 |
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
}
|
42 |
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
|
|
|
|
|
|
52 |
}
|
53 |
|
54 |
async run() {
|
@@ -59,21 +72,124 @@ export default class Yunzai extends EventEmitter {
|
|
59 |
this.emit("online", this)
|
60 |
}
|
61 |
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
req.res.redirect("https://github.com/TimeRainStarSky/Yunzai")
|
66 |
-
})
|
67 |
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
})
|
75 |
}
|
76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
getFriendArray() {
|
78 |
const array = []
|
79 |
for (const bot_id of this.uin)
|
@@ -185,7 +301,7 @@ export default class Yunzai extends EventEmitter {
|
|
185 |
return false
|
186 |
}
|
187 |
|
188 |
-
async
|
189 |
if (typeof fnc != "function") {
|
190 |
const { self_id, user_id } = fnc
|
191 |
fnc = data => data.self_id == self_id && data.user_id == user_id
|
@@ -210,7 +326,7 @@ export default class Yunzai extends EventEmitter {
|
|
210 |
}
|
211 |
|
212 |
getMasterMsg() {
|
213 |
-
return this.
|
214 |
cfg.master[data.self_id]?.includes(String(data.user_id)))
|
215 |
}
|
216 |
|
|
|
7 |
import http from "http"
|
8 |
import { WebSocketServer } from "ws"
|
9 |
import _ from "lodash"
|
10 |
+
import fs from "node:fs"
|
11 |
+
import fetch from "node-fetch"
|
12 |
+
import { randomUUID } from "node:crypto"
|
13 |
+
import { exec } from "child_process"
|
14 |
+
import { fileTypeFromBuffer } from "file-type"
|
15 |
+
import md5 from "md5"
|
16 |
|
17 |
export default class Yunzai extends EventEmitter {
|
18 |
constructor() {
|
19 |
super()
|
20 |
this.uin = []
|
21 |
this.adapter = []
|
22 |
+
|
23 |
this.express = express()
|
24 |
this.server = http.createServer(this.express)
|
25 |
+
|
26 |
+
this.server.on("upgrade", (...args) => this.wsConnect(...args))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
this.wss = new WebSocketServer({ noServer: true })
|
28 |
this.wsf = {}
|
29 |
+
|
30 |
+
this.fs = {}
|
31 |
+
this.express.use("/File", (...args) => this.fileSend(...args))
|
32 |
+
this.fileToUrl("resources/http/File/404.jpg", { name: 404, time: 0 })
|
33 |
+
this.fileToUrl("resources/http/File/timeout.jpg", { name: "timeout", time: 0 })
|
34 |
}
|
35 |
|
36 |
+
wsConnect(req, socket, head) {
|
37 |
+
this.wss.handleUpgrade(req, socket, head, conn => {
|
38 |
+
conn.id = `${req.connection.remoteAddress}-${req.headers["sec-websocket-key"]}`
|
39 |
+
this.makeLog("mark", `${logger.blue(`[${conn.id} <=> ws://${req.headers.host}${req.url}]`)} 建立连接:${JSON.stringify(req.headers)}`)
|
40 |
+
conn.on("error", logger.error)
|
41 |
+
conn.on("close", () => this.makeLog("mark", `${logger.blue(`[${conn.id} <≠> ws://${req.headers.host}${req.url}]`)} 断开连接`))
|
42 |
+
conn.on("message", msg => this.makeLog("debug", `${logger.blue(`[${conn.id} => ws://${req.headers.host}${req.url}]`)} 消息:${String(msg).trim()}`))
|
43 |
+
conn.sendMsg = msg => {
|
44 |
+
if (!Buffer.isBuffer(msg)) msg = this.String(msg)
|
45 |
+
this.makeLog("debug", `${logger.blue(`[${conn.id} <= ws://${req.headers.host}${req.url}]`)} 消息:${msg}`)
|
46 |
+
return conn.send(msg)
|
47 |
+
}
|
48 |
+
for (const i of this.wsf[req.url.split("/")[1]] || [])
|
49 |
+
i(conn, req, socket, head)
|
50 |
+
})
|
51 |
}
|
52 |
|
53 |
+
serverLoad() {
|
54 |
+
this.express.use(req => {
|
55 |
+
logger.mark(`${logger.blue(`[${req.ip} => http://${req.headers.host}${req.url}]`)} HTTP ${req.method} 请求:${JSON.stringify(req.headers)}`)
|
56 |
+
req.res.redirect("https://github.com/TimeRainStarSky/Yunzai")
|
57 |
+
})
|
58 |
+
|
59 |
+
this.server.listen(cfg.bot.port, () => {
|
60 |
+
logger.mark(`启动 HTTP 服务器:${logger.green(`http://[${this.server.address().address}]:${this.server.address().port}`)}`)
|
61 |
+
const url = cfg.bot.url.replace(/^http/, "ws")
|
62 |
+
for (const i of Object.keys(this.wsf))
|
63 |
+
logger.info(`${i} 连接地址:${logger.blue(`${url}/${i}`)}`)
|
64 |
+
})
|
65 |
}
|
66 |
|
67 |
async run() {
|
|
|
72 |
this.emit("online", this)
|
73 |
}
|
74 |
|
75 |
+
sleep(time) {
|
76 |
+
return new Promise(resolve => setTimeout(resolve, time))
|
77 |
+
}
|
|
|
|
|
78 |
|
79 |
+
String(data) {
|
80 |
+
switch (typeof data) {
|
81 |
+
case "string":
|
82 |
+
return data
|
83 |
+
case "object":
|
84 |
+
return JSON.stringify(data)
|
85 |
+
}
|
86 |
+
return String(data)
|
87 |
+
}
|
88 |
+
|
89 |
+
Buffer(data, opts = {}) {
|
90 |
+
if (Buffer.isBuffer(data)) return data
|
91 |
+
data = this.String(data)
|
92 |
+
|
93 |
+
if (data.match(/^base64:\/\//)) {
|
94 |
+
return Buffer.from(data.replace(/^base64:\/\//, ""), "base64")
|
95 |
+
} else if (data.match(/^https?:\/\//)) {
|
96 |
+
if (opts.http) return data
|
97 |
+
return (async () => Buffer.from(await (await fetch(data)).arrayBuffer()))()
|
98 |
+
} else if (fs.existsSync(data.replace(/^file:\/\//, ""))) {
|
99 |
+
if (opts.file) return data
|
100 |
+
return Buffer.from(fs.readFileSync(data.replace(/^file:\/\//, "")))
|
101 |
+
}
|
102 |
+
return data
|
103 |
+
}
|
104 |
+
|
105 |
+
async fileType(data, name) {
|
106 |
+
const file = {}
|
107 |
+
try {
|
108 |
+
if (Buffer.isBuffer(data)) {
|
109 |
+
file.url = name || "Buffer"
|
110 |
+
file.buffer = data
|
111 |
+
} else {
|
112 |
+
file.url = data.replace(/^base64:\/\/.*/, "base64://...")
|
113 |
+
file.buffer = await this.Buffer(data)
|
114 |
+
}
|
115 |
+
if (Buffer.isBuffer(file.buffer)) {
|
116 |
+
file.type = await fileTypeFromBuffer(file.buffer)
|
117 |
+
file.md5 = md5(file.buffer)
|
118 |
+
file.name = name || `${Date.now()}.${file.md5.slice(0,8)}.${file.type.ext}`
|
119 |
+
} else {
|
120 |
+
file.name = name || `${Date.now()}-path.basename(file.buffer)`
|
121 |
+
}
|
122 |
+
} catch (err) {
|
123 |
+
logger.error(`文件类型检测错误:${logger.red(err)}`)
|
124 |
+
}
|
125 |
+
return file
|
126 |
+
}
|
127 |
+
|
128 |
+
async fileToUrl(file, opts = {}) {
|
129 |
+
const { name, time = 60000, times } = opts
|
130 |
+
|
131 |
+
file = await this.fileType(file, name)
|
132 |
+
if (!Buffer.isBuffer(file.buffer)) return file.buffer
|
133 |
+
if (!file.name) file.name = randomUUID()
|
134 |
+
|
135 |
+
if (typeof times == "number") file.times = times
|
136 |
+
this.fs[file.name] = file
|
137 |
+
if (time) setTimeout(() => this.fs[file.name] = this.fs.timeout, time)
|
138 |
+
return `${cfg.bot.url}/File/${file.name}`
|
139 |
+
}
|
140 |
+
|
141 |
+
fileSend(req) {
|
142 |
+
const url = req.url.replace(/^\//, "")
|
143 |
+
let file = this.fs[url]
|
144 |
+
if (!file) file = this.fs[404]
|
145 |
+
|
146 |
+
if (typeof file.times == "number") {
|
147 |
+
if (file.times > 0) file.times = file.times-1
|
148 |
+
else file = this.fs.timeout
|
149 |
+
}
|
150 |
+
|
151 |
+
if (file.type?.mime)
|
152 |
+
req.res.setHeader("Content-Type", file.type.mime)
|
153 |
+
|
154 |
+
logger.mark(`${logger.blue(`[${req.ip} => http://${req.headers.host}/File/${url}]`)} HTTP ${req.method} 请求:${JSON.stringify(req.headers)}`)
|
155 |
+
logger.mark(`${logger.blue(`[${req.ip} <= http://${req.headers.host}/File/${url}]`)} 发送文件:${file.name}(${file.url} ${(file.buffer.length/1024).toFixed(2)}KB)`)
|
156 |
+
req.res.send(file.buffer)
|
157 |
+
}
|
158 |
+
|
159 |
+
async exec(cmd) {
|
160 |
+
return new Promise(resolve => {
|
161 |
+
this.makeLog("mark", `[命令执行开始] ${logger.blue(cmd)}`)
|
162 |
+
exec(cmd, (error, stdout, stderr) => {
|
163 |
+
this.makeLog("mark", `[命令执行完成] ${logger.blue(cmd)}${stdout?`\n${this.String(stdout).trim()}`:""}${stderr?logger.red(`\n${this.String(stderr).trim()}`):""}`)
|
164 |
+
if (error) this.makeLog("mark", `[命令执行错误] ${logger.blue(cmd)}\n${logger.red(this.String(error).trim())}`)
|
165 |
+
resolve({ error, stdout, stderr })
|
166 |
+
})
|
167 |
})
|
168 |
}
|
169 |
|
170 |
+
makeLog(level, msg, id) {
|
171 |
+
const log = []
|
172 |
+
if (id) log.push(logger.blue(`[${id}]`))
|
173 |
+
for (const i of Array.isArray(msg) ? msg : [msg]) {
|
174 |
+
if (i?.replace)
|
175 |
+
log.push(_.truncate(i.replace(/{"type":"Buffer","data":\[.*?\]}/g, "(Buffer)"), { length: cfg.bot.log_length }))
|
176 |
+
else
|
177 |
+
log.push(i)
|
178 |
+
}
|
179 |
+
logger[level](...log)
|
180 |
+
}
|
181 |
+
|
182 |
+
em(name = "", data = {}) {
|
183 |
+
if (data.self_id)
|
184 |
+
Object.defineProperty(data, "bot", { value: Bot[data.self_id] })
|
185 |
+
while (true) {
|
186 |
+
this.emit(name, data)
|
187 |
+
const i = name.lastIndexOf(".")
|
188 |
+
if (i == -1) break
|
189 |
+
name = name.slice(0, i)
|
190 |
+
}
|
191 |
+
}
|
192 |
+
|
193 |
getFriendArray() {
|
194 |
const array = []
|
195 |
for (const bot_id of this.uin)
|
|
|
301 |
return false
|
302 |
}
|
303 |
|
304 |
+
async getTextMsg(fnc = () => true) {
|
305 |
if (typeof fnc != "function") {
|
306 |
const { self_id, user_id } = fnc
|
307 |
fnc = data => data.self_id == self_id && data.user_id == user_id
|
|
|
326 |
}
|
327 |
|
328 |
getMasterMsg() {
|
329 |
+
return this.getTextMsg(data =>
|
330 |
cfg.master[data.self_id]?.includes(String(data.user_id)))
|
331 |
}
|
332 |
|
Yunzai/lib/config/config.js
CHANGED
@@ -18,11 +18,11 @@ class Cfg {
|
|
18 |
let path = "config/config/"
|
19 |
let pathDef = "config/default_config/"
|
20 |
const files = fs.readdirSync(pathDef).filter(file => file.endsWith(".yaml"))
|
21 |
-
for (
|
22 |
if (!fs.existsSync(`${path}${file}`))
|
23 |
fs.copyFileSync(`${pathDef}${file}`, `${path}${file}`)
|
24 |
-
|
25 |
-
|
26 |
}
|
27 |
|
28 |
/** Bot配置 */
|
@@ -69,10 +69,12 @@ class Cfg {
|
|
69 |
const masters = {}
|
70 |
for (let i of master) {
|
71 |
i = i.split(":")
|
72 |
-
|
73 |
-
|
|
|
|
|
74 |
else
|
75 |
-
masters[
|
76 |
}
|
77 |
return masters
|
78 |
}
|
|
|
18 |
let path = "config/config/"
|
19 |
let pathDef = "config/default_config/"
|
20 |
const files = fs.readdirSync(pathDef).filter(file => file.endsWith(".yaml"))
|
21 |
+
for (const file of files)
|
22 |
if (!fs.existsSync(`${path}${file}`))
|
23 |
fs.copyFileSync(`${pathDef}${file}`, `${path}${file}`)
|
24 |
+
for (const i of ["data", "temp"])
|
25 |
+
if (!fs.existsSync(i)) fs.mkdirSync(i)
|
26 |
}
|
27 |
|
28 |
/** Bot配置 */
|
|
|
69 |
const masters = {}
|
70 |
for (let i of master) {
|
71 |
i = i.split(":")
|
72 |
+
const bot_id = i.shift()
|
73 |
+
const user_id = i.join(":")
|
74 |
+
if (Array.isArray(masters[bot_id]))
|
75 |
+
masters[bot_id].push(user_id)
|
76 |
else
|
77 |
+
masters[bot_id] = [user_id]
|
78 |
}
|
79 |
return masters
|
80 |
}
|
Yunzai/lib/config/init.js
CHANGED
@@ -1,28 +1,35 @@
|
|
1 |
-
import setLog from
|
2 |
-
import redisInit from
|
3 |
-
import { checkRun } from
|
4 |
-
import cfg from
|
5 |
|
6 |
/** 设置标题 */
|
7 |
-
process.title =
|
8 |
|
9 |
/** 设置时区 */
|
10 |
-
process.env.TZ =
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
|
12 |
/** 捕获未处理的Promise错误 */
|
13 |
-
process.on(
|
14 |
-
if (logger)
|
15 |
-
|
16 |
-
} else {
|
17 |
-
console.log(error)
|
18 |
-
}
|
19 |
})
|
20 |
|
21 |
/** 退出事件 */
|
22 |
-
process.on(
|
23 |
-
if (typeof redis !=
|
24 |
await redis.save()
|
25 |
-
|
|
|
|
|
|
|
|
|
26 |
})
|
27 |
|
28 |
await checkInit()
|
@@ -32,11 +39,11 @@ async function checkInit() {
|
|
32 |
/** 日志设置 */
|
33 |
setLog()
|
34 |
|
35 |
-
logger.mark(
|
36 |
logger.mark(logger.yellow(`TRSS-Yunzai v${cfg.package.version} 启动中...`))
|
37 |
-
logger.mark(logger.cyan(
|
38 |
|
39 |
await redisInit()
|
40 |
|
41 |
checkRun()
|
42 |
-
}
|
|
|
1 |
+
import setLog from "./log.js"
|
2 |
+
import redisInit from "./redis.js"
|
3 |
+
import { checkRun } from "./check.js"
|
4 |
+
import cfg from "./config.js"
|
5 |
|
6 |
/** 设置标题 */
|
7 |
+
process.title = `TRSS Yunzai v${cfg.package.version} © 2023 - 2024 TimeRainStarSky`
|
8 |
|
9 |
/** 设置时区 */
|
10 |
+
process.env.TZ = "Asia/Shanghai"
|
11 |
+
|
12 |
+
/** 捕获未处理的错误 */
|
13 |
+
process.on("uncaughtException", error => {
|
14 |
+
if (typeof logger == "undefined") console.log(error)
|
15 |
+
else logger.error(error)
|
16 |
+
})
|
17 |
|
18 |
/** 捕获未处理的Promise错误 */
|
19 |
+
process.on("unhandledRejection", (error, promise) => {
|
20 |
+
if (typeof logger == "undefined") console.log(error)
|
21 |
+
else logger.error(error)
|
|
|
|
|
|
|
22 |
})
|
23 |
|
24 |
/** 退出事件 */
|
25 |
+
process.on("exit", async code => {
|
26 |
+
if (typeof redis != "undefined" && typeof test == "undefined")
|
27 |
await redis.save()
|
28 |
+
|
29 |
+
if (typeof logger == "undefined")
|
30 |
+
console.log("TRSS-Yunzai 已停止运行")
|
31 |
+
else
|
32 |
+
logger.mark(logger.magenta("TRSS-Yunzai 已停止运行"))
|
33 |
})
|
34 |
|
35 |
await checkInit()
|
|
|
39 |
/** 日志设置 */
|
40 |
setLog()
|
41 |
|
42 |
+
logger.mark("----^_^----")
|
43 |
logger.mark(logger.yellow(`TRSS-Yunzai v${cfg.package.version} 启动中...`))
|
44 |
+
logger.mark(logger.cyan("https://github.com/TimeRainStarSky/Yunzai"))
|
45 |
|
46 |
await redisInit()
|
47 |
|
48 |
checkRun()
|
49 |
+
}
|
Yunzai/lib/config/redis.js
CHANGED
@@ -44,6 +44,7 @@ export default async function redisInit() {
|
|
44 |
})
|
45 |
|
46 |
/** 全局变量 redis */
|
|
|
47 |
global.redis = client
|
48 |
logger.info("Redis 连接成功")
|
49 |
return client
|
|
|
44 |
})
|
45 |
|
46 |
/** 全局变量 redis */
|
47 |
+
client.url = redisUrl
|
48 |
global.redis = client
|
49 |
logger.info("Redis 连接成功")
|
50 |
return client
|
Yunzai/lib/events/connect.js
CHANGED
@@ -13,10 +13,10 @@ export default class connectEvent extends EventListener {
|
|
13 |
if (!Bot.uin.includes(e.self_id))
|
14 |
Bot.uin.push(e.self_id)
|
15 |
|
16 |
-
if (!cfg.bot.
|
17 |
const key = `Yz:loginMsg:${e.self_id}`
|
18 |
if (await redis.get(key)) return
|
19 |
-
redis.set(key, "1", { EX: cfg.bot.online_msg_exp })
|
20 |
for (const i of cfg.master[e.self_id] || [])
|
21 |
e.bot.pickFriend(i).sendMsg(`欢迎使用【TRSS-Yunzai v${cfg.package.version}】\n【#帮助】查看指令说明\n【#状态】查看运行状态\n【#日志】查看运行日志\n【#重启】重新启动\n【#更新】拉取 Git 更新\n【#全部更新】更新全部插件\n【#更新日志】查看更新日志\n【#设置主人】设置主人账号\n【#安装插件】查看可安装插件`)
|
22 |
}
|
|
|
13 |
if (!Bot.uin.includes(e.self_id))
|
14 |
Bot.uin.push(e.self_id)
|
15 |
|
16 |
+
if (!cfg.bot.online_msg_exp) return
|
17 |
const key = `Yz:loginMsg:${e.self_id}`
|
18 |
if (await redis.get(key)) return
|
19 |
+
redis.set(key, "1", { EX: cfg.bot.online_msg_exp*60 })
|
20 |
for (const i of cfg.master[e.self_id] || [])
|
21 |
e.bot.pickFriend(i).sendMsg(`欢迎使用【TRSS-Yunzai v${cfg.package.version}】\n【#帮助】查看指令说明\n【#状态】查看运行状态\n【#日志】查看运行日志\n【#重启】重新启动\n【#更新】拉取 Git 更新\n【#全部更新】更新全部插件\n【#更新日志】查看更新日志\n【#设置主人】设置主人账号\n【#安装插件】查看可安装插件`)
|
22 |
}
|
Yunzai/lib/events/online.js
CHANGED
@@ -5,14 +5,14 @@ import cfg from '../config/config.js'
|
|
5 |
* 监听上线事件
|
6 |
*/
|
7 |
export default class onlineEvent extends EventListener {
|
8 |
-
constructor
|
9 |
super({
|
10 |
event: 'online',
|
11 |
once: true
|
12 |
})
|
13 |
}
|
14 |
|
15 |
-
async execute
|
16 |
logger.mark('----^_^----')
|
17 |
}
|
18 |
}
|
|
|
5 |
* 监听上线事件
|
6 |
*/
|
7 |
export default class onlineEvent extends EventListener {
|
8 |
+
constructor() {
|
9 |
super({
|
10 |
event: 'online',
|
11 |
once: true
|
12 |
})
|
13 |
}
|
14 |
|
15 |
+
async execute() {
|
16 |
logger.mark('----^_^----')
|
17 |
}
|
18 |
}
|
Yunzai/lib/modules/oicq/index.js
CHANGED
@@ -2,20 +2,12 @@ import fs from "node:fs"
|
|
2 |
import path from "node:path"
|
3 |
|
4 |
function toSegment(type, data) {
|
5 |
-
for (const i in data)
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
data.name = path.basename(data[i])
|
11 |
-
data[i] = `base64://${fs.readFileSync(data[i].replace(/^file:\/\//, "")).toString("base64")}`
|
12 |
-
}
|
13 |
-
break
|
14 |
-
case "object":
|
15 |
-
if (Buffer.isBuffer(data[i]))
|
16 |
-
data[i] = `base64://${data[i].toString("base64")}`
|
17 |
}
|
18 |
-
}
|
19 |
return { type, ...data }
|
20 |
}
|
21 |
|
@@ -23,6 +15,15 @@ const segment = new class segment {
|
|
23 |
custom(type, data) {
|
24 |
return toSegment(type, data)
|
25 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
image(file, name) {
|
27 |
return toSegment("image", { file, name })
|
28 |
}
|
|
|
2 |
import path from "node:path"
|
3 |
|
4 |
function toSegment(type, data) {
|
5 |
+
for (const i in data)
|
6 |
+
if (typeof data[i] == "string" && (i == "file" || data[i].match(/^file:\/\//)) && fs.existsSync(data[i].replace(/^file:\/\//, ""))) {
|
7 |
+
if (i == "file" && !data.name)
|
8 |
+
data.name = `${Date.now()}-${path.basename(data[i])}`
|
9 |
+
data[i] = fs.readFileSync(data[i].replace(/^file:\/\//, ""))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
}
|
|
|
11 |
return { type, ...data }
|
12 |
}
|
13 |
|
|
|
15 |
custom(type, data) {
|
16 |
return toSegment(type, data)
|
17 |
}
|
18 |
+
raw(data) {
|
19 |
+
return toSegment("raw", { data })
|
20 |
+
}
|
21 |
+
button(...data) {
|
22 |
+
return toSegment("button", { data })
|
23 |
+
}
|
24 |
+
markdown(data) {
|
25 |
+
return toSegment("markdown", { data })
|
26 |
+
}
|
27 |
image(file, name) {
|
28 |
return toSegment("image", { file, name })
|
29 |
}
|
Yunzai/lib/plugins/loader.js
CHANGED
@@ -134,7 +134,7 @@ class PluginsLoader {
|
|
134 |
for (let val of files) {
|
135 |
let filepath = "../../plugins/" + val.name
|
136 |
let tmp = {
|
137 |
-
name: val.name
|
138 |
}
|
139 |
if (val.isFile()) {
|
140 |
if (!val.name.endsWith(".js")) continue
|
@@ -229,8 +229,16 @@ class PluginsLoader {
|
|
229 |
|
230 |
// 判断是否是星铁命令,若是星铁命令则标准化处理
|
231 |
// e.isSr = true,且命令标准化为 #星铁 开头
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
232 |
if (this.srReg.test(e.msg)) {
|
233 |
-
e.
|
234 |
e.msg = e.msg.replace(this.srReg, "#星铁")
|
235 |
}
|
236 |
|
@@ -260,7 +268,7 @@ class PluginsLoader {
|
|
260 |
e.logFnc = `[${plugin.name}][${v.fnc}]`
|
261 |
|
262 |
if (v.log !== false) {
|
263 |
-
logger.
|
264 |
}
|
265 |
|
266 |
/** 判断权限 */
|
@@ -521,9 +529,7 @@ class PluginsLoader {
|
|
521 |
try {
|
522 |
res = await e.replyNew(msg)
|
523 |
} catch (err) {
|
524 |
-
|
525 |
-
msg = lodash.truncate(JSON.stringify(msg), { length: 300 })
|
526 |
-
logger.error(`发送消息错误:${msg}`)
|
527 |
logger.error(err)
|
528 |
}
|
529 |
|
@@ -631,25 +637,19 @@ class PluginsLoader {
|
|
631 |
if (e.isGroup && e?.group?.mute_left > 0) return false
|
632 |
if (!e.message || e.isPrivate) return true
|
633 |
|
634 |
-
|
635 |
|
636 |
-
if (config.groupCD && this.groupCD[e.group_id])
|
637 |
return false
|
638 |
-
|
639 |
-
if (config.singleCD && this.singleCD[`${e.group_id}.${e.user_id}`])
|
640 |
return false
|
641 |
-
}
|
642 |
|
643 |
-
|
|
|
644 |
|
645 |
-
|
646 |
-
|
647 |
-
return false
|
648 |
-
}
|
649 |
-
msgThrottle[msgId] = true
|
650 |
-
setTimeout(() => {
|
651 |
-
delete msgThrottle[msgId]
|
652 |
-
}, 200)
|
653 |
|
654 |
return true
|
655 |
}
|
|
|
134 |
for (let val of files) {
|
135 |
let filepath = "../../plugins/" + val.name
|
136 |
let tmp = {
|
137 |
+
name: val.name
|
138 |
}
|
139 |
if (val.isFile()) {
|
140 |
if (!val.name.endsWith(".js")) continue
|
|
|
229 |
|
230 |
// 判断是否是星铁命令,若是星铁命令则标准化处理
|
231 |
// e.isSr = true,且命令标准化为 #星铁 开头
|
232 |
+
Object.defineProperty(e, "isSr", {
|
233 |
+
get: () => e.game === "sr",
|
234 |
+
set: (v) => e.game = v ? "sr" : "gs"
|
235 |
+
})
|
236 |
+
Object.defineProperty(e, "isGs", {
|
237 |
+
get: () => e.game === "gs",
|
238 |
+
set: (v) => e.game = v ? "gs" : "sr"
|
239 |
+
})
|
240 |
if (this.srReg.test(e.msg)) {
|
241 |
+
e.game = "sr"
|
242 |
e.msg = e.msg.replace(this.srReg, "#星铁")
|
243 |
}
|
244 |
|
|
|
268 |
e.logFnc = `[${plugin.name}][${v.fnc}]`
|
269 |
|
270 |
if (v.log !== false) {
|
271 |
+
logger.info(`${e.logFnc}${e.logText} ${lodash.truncate(e.msg, { length: 80 })}`)
|
272 |
}
|
273 |
|
274 |
/** 判断权限 */
|
|
|
529 |
try {
|
530 |
res = await e.replyNew(msg)
|
531 |
} catch (err) {
|
532 |
+
Bot.makeLog("error", `发送消息错误:${Bot.String(msg)}`, e.self_id)
|
|
|
|
|
533 |
logger.error(err)
|
534 |
}
|
535 |
|
|
|
637 |
if (e.isGroup && e?.group?.mute_left > 0) return false
|
638 |
if (!e.message || e.isPrivate) return true
|
639 |
|
640 |
+
const config = cfg.getGroup(e.self_id, e.group_id)
|
641 |
|
642 |
+
if (config.groupCD && this.groupCD[e.group_id])
|
643 |
return false
|
644 |
+
|
645 |
+
if (config.singleCD && this.singleCD[`${e.group_id}.${e.user_id}`])
|
646 |
return false
|
|
|
647 |
|
648 |
+
const msgId = `${e.self_id}:${e.user_id}:${e.raw_message}`
|
649 |
+
if (this.msgThrottle[msgId]) return false
|
650 |
|
651 |
+
this.msgThrottle[msgId] = true
|
652 |
+
setTimeout(() => delete this.msgThrottle[msgId], 1000)
|
|
|
|
|
|
|
|
|
|
|
|
|
653 |
|
654 |
return true
|
655 |
}
|
Yunzai/lib/plugins/plugin.js
CHANGED
@@ -1,3 +1,5 @@
|
|
|
|
|
|
1 |
let stateArr = {}
|
2 |
|
3 |
export default class plugin {
|
@@ -116,4 +118,11 @@ export default class plugin {
|
|
116 |
delete stateArr[this.conKey(isGroup)][type]
|
117 |
}
|
118 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
119 |
}
|
|
|
1 |
+
import { Common } from '#miao'
|
2 |
+
|
3 |
let stateArr = {}
|
4 |
|
5 |
export default class plugin {
|
|
|
118 |
delete stateArr[this.conKey(isGroup)][type]
|
119 |
}
|
120 |
}
|
121 |
+
|
122 |
+
async renderImg (plugin, tpl, data, cfg) {
|
123 |
+
return Common.render(plugin, tpl, data, {
|
124 |
+
...cfg,
|
125 |
+
e: this.e
|
126 |
+
})
|
127 |
+
}
|
128 |
}
|
Yunzai/lib/plugins/runtime.js
CHANGED
@@ -77,7 +77,6 @@ export default class Runtime {
|
|
77 |
await MysInfo.initCache()
|
78 |
let runtime = new Runtime(e)
|
79 |
e.runtime = runtime
|
80 |
-
e.game = e.isSr ? 'sr' : 'gs'
|
81 |
await runtime.initUser()
|
82 |
return runtime
|
83 |
}
|
@@ -88,7 +87,7 @@ export default class Runtime {
|
|
88 |
if (user) {
|
89 |
e.user = new Proxy(user, {
|
90 |
get (self, key, receiver) {
|
91 |
-
let game = e.
|
92 |
let fnMap = {
|
93 |
uid: 'getUid',
|
94 |
uidList: 'getUidList',
|
@@ -238,7 +237,11 @@ export default class Runtime {
|
|
238 |
}
|
239 |
let ret = true
|
240 |
if (base64) {
|
241 |
-
|
|
|
|
|
|
|
|
|
242 |
}
|
243 |
return cfg.retType === 'msgId' ? ret : true
|
244 |
}
|
|
|
77 |
await MysInfo.initCache()
|
78 |
let runtime = new Runtime(e)
|
79 |
e.runtime = runtime
|
|
|
80 |
await runtime.initUser()
|
81 |
return runtime
|
82 |
}
|
|
|
87 |
if (user) {
|
88 |
e.user = new Proxy(user, {
|
89 |
get (self, key, receiver) {
|
90 |
+
let game = e.game
|
91 |
let fnMap = {
|
92 |
uid: 'getUid',
|
93 |
uidList: 'getUidList',
|
|
|
237 |
}
|
238 |
let ret = true
|
239 |
if (base64) {
|
240 |
+
if (cfg.recallMsg) {
|
241 |
+
ret = await this.e.reply(base64, false, {})
|
242 |
+
} else {
|
243 |
+
ret = await this.e.reply(base64)
|
244 |
+
}
|
245 |
}
|
246 |
return cfg.retType === 'msgId' ? ret : true
|
247 |
}
|
Yunzai/lib/plugins/stdin.js
CHANGED
@@ -1,8 +1,6 @@
|
|
1 |
-
import fetch from "node-fetch"
|
2 |
import fs from "node:fs"
|
3 |
import path from "node:path"
|
4 |
import common from "../common/common.js"
|
5 |
-
import { fileTypeFromBuffer } from "file-type"
|
6 |
|
7 |
Bot.adapter.push(new class stdinAdapter {
|
8 |
constructor() {
|
@@ -12,59 +10,36 @@ Bot.adapter.push(new class stdinAdapter {
|
|
12 |
common.mkdirs(this.path)
|
13 |
}
|
14 |
|
15 |
-
async makeBuffer(file) {
|
16 |
-
if (file.match(/^base64:\/\//))
|
17 |
-
return Buffer.from(file.replace(/^base64:\/\//, ""), "base64")
|
18 |
-
else if (file.match(/^https?:\/\//))
|
19 |
-
return Buffer.from(await (await fetch(file)).arrayBuffer())
|
20 |
-
else if (fs.existsSync(file))
|
21 |
-
return Buffer.from(fs.readFileSync(file))
|
22 |
-
return file
|
23 |
-
}
|
24 |
-
|
25 |
-
async fileType(data) {
|
26 |
-
const file = {}
|
27 |
-
try {
|
28 |
-
file.url = data.replace(/^base64:\/\/.*/, "base64://...")
|
29 |
-
file.buffer = await this.makeBuffer(data)
|
30 |
-
file.type = await fileTypeFromBuffer(file.buffer)
|
31 |
-
file.path = `${this.path}${Date.now()}.${file.type.ext}`
|
32 |
-
} catch (err) {
|
33 |
-
logger.error(`文件类型检测错误:${logger.red(err)}`)
|
34 |
-
}
|
35 |
-
return file
|
36 |
-
}
|
37 |
-
|
38 |
async sendMsg(msg) {
|
39 |
if (!Array.isArray(msg))
|
40 |
msg = [msg]
|
41 |
for (let i of msg) {
|
42 |
if (typeof i != "object")
|
43 |
-
i = { type: "text",
|
44 |
-
else if (!i.data)
|
45 |
-
i = { type: i.type, data: { ...i, type: undefined }}
|
46 |
|
47 |
let file
|
48 |
-
if (i.
|
49 |
-
file = await
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
switch (i.type) {
|
52 |
case "text":
|
53 |
-
if (i.
|
54 |
-
i.
|
55 |
-
logger.info(`${logger.blue(`[${this.id}]`)} 发送文本:${i.
|
56 |
break
|
57 |
case "image":
|
58 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送图片:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
59 |
-
fs.writeFileSync(file.path, file.buffer)
|
60 |
break
|
61 |
case "record":
|
62 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送音频:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
63 |
-
fs.writeFileSync(file.path, file.buffer)
|
64 |
break
|
65 |
case "video":
|
66 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送视频:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
67 |
-
fs.writeFileSync(file.path, file.buffer)
|
68 |
break
|
69 |
case "reply":
|
70 |
break
|
@@ -88,7 +63,7 @@ Bot.adapter.push(new class stdinAdapter {
|
|
88 |
}
|
89 |
|
90 |
async sendFile(file, name = path.basename(file)) {
|
91 |
-
const buffer = await
|
92 |
if (!Buffer.isBuffer(buffer)) {
|
93 |
logger.error(`${logger.blue(`[${this.id}]`)} 发送文件错误:找不到文件 ${logger.red(file)}`)
|
94 |
return false
|
|
|
|
|
1 |
import fs from "node:fs"
|
2 |
import path from "node:path"
|
3 |
import common from "../common/common.js"
|
|
|
4 |
|
5 |
Bot.adapter.push(new class stdinAdapter {
|
6 |
constructor() {
|
|
|
10 |
common.mkdirs(this.path)
|
11 |
}
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
async sendMsg(msg) {
|
14 |
if (!Array.isArray(msg))
|
15 |
msg = [msg]
|
16 |
for (let i of msg) {
|
17 |
if (typeof i != "object")
|
18 |
+
i = { type: "text", text: i }
|
|
|
|
|
19 |
|
20 |
let file
|
21 |
+
if (i.file) {
|
22 |
+
file = await Bot.fileType(i.file, i.name)
|
23 |
+
if (Buffer.isBuffer(file.buffer)) {
|
24 |
+
file.path = `${this.path}${file.name || Date.now()}`
|
25 |
+
fs.writeFileSync(file.path, file.buffer)
|
26 |
+
}
|
27 |
+
}
|
28 |
|
29 |
switch (i.type) {
|
30 |
case "text":
|
31 |
+
if (i.text.match("\n"))
|
32 |
+
i.text = `\n${i.text}`
|
33 |
+
logger.info(`${logger.blue(`[${this.id}]`)} 发送文本:${i.text}`)
|
34 |
break
|
35 |
case "image":
|
36 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送图片:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
|
|
37 |
break
|
38 |
case "record":
|
39 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送音频:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
|
|
40 |
break
|
41 |
case "video":
|
42 |
logger.info(`${logger.blue(`[${this.id}]`)} 发送视频:${file.url}\n文件已保存到:${logger.cyan(file.path)}`)
|
|
|
43 |
break
|
44 |
case "reply":
|
45 |
break
|
|
|
63 |
}
|
64 |
|
65 |
async sendFile(file, name = path.basename(file)) {
|
66 |
+
const buffer = await Bot.Buffer(file)
|
67 |
if (!Buffer.isBuffer(buffer)) {
|
68 |
logger.error(`${logger.blue(`[${this.id}]`)} 发送文件错误:找不到文件 ${logger.red(file)}`)
|
69 |
return false
|
Yunzai/lib/tools/log.js
ADDED
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import fs from "node:fs"
|
2 |
+
import childProcess from "child_process"
|
3 |
+
|
4 |
+
const _path = process.cwd()
|
5 |
+
|
6 |
+
fs.readFile(`${_path}/config/pm2/pm2.json`, `utf8`, (err, data) => {
|
7 |
+
if (err) {
|
8 |
+
console.log('pm2.json文件读取错误:', err)
|
9 |
+
return
|
10 |
+
}
|
11 |
+
|
12 |
+
try {
|
13 |
+
const config = JSON.parse(data)
|
14 |
+
if (config.apps && config.apps.length > 0 && config.apps[0].name) {
|
15 |
+
const appName = config.apps[0].name
|
16 |
+
runPm2Logs(appName)
|
17 |
+
} else {
|
18 |
+
console.log('读取失败:无法在pm2.json中找到name数组')
|
19 |
+
}
|
20 |
+
} catch (parseError) {
|
21 |
+
console.log('读取失败:json文件解析发生了错误', parseError)
|
22 |
+
}
|
23 |
+
})
|
24 |
+
|
25 |
+
function runPm2Logs(appName) {
|
26 |
+
const command = process.platform === 'win32' ? 'pm2.cmd' : 'pm2'
|
27 |
+
const args = ['logs', '--lines', '400', appName]
|
28 |
+
const pm2LogsProcess = childProcess.spawn(command, args, { stdio: 'inherit' })
|
29 |
+
pm2LogsProcess.on('exit', (code) => {
|
30 |
+
if (code !== 0) {
|
31 |
+
console.error(`pm2 logs process exited with code ${code}`)
|
32 |
+
}
|
33 |
+
})
|
34 |
+
}
|
Yunzai/package-lock.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
Yunzai/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
{
|
2 |
"name": "trss-yunzai",
|
3 |
-
"version": "3.1.
|
4 |
"author": "TimeRainStarSky, Yoimiya-Kokomi, Le-niao",
|
5 |
"description": "Bot",
|
6 |
"main": "app.js",
|
@@ -13,37 +13,36 @@
|
|
13 |
"start": "pm2 start ./config/pm2/pm2.json",
|
14 |
"stop": "pm2 stop ./config/pm2/pm2.json",
|
15 |
"restart": "pm2 restart ./config/pm2/pm2.json",
|
16 |
-
"log": "node ./lib/tools/
|
17 |
},
|
18 |
"dependencies": {
|
19 |
"art-template": "^4.13.2",
|
20 |
"chalk": "^5.3.0",
|
21 |
"chokidar": "^3.5.3",
|
22 |
"express": "^4.18.2",
|
23 |
-
"file-type": "^18.
|
24 |
"https-proxy-agent": "7.0.2",
|
25 |
"image-size": "^1.0.2",
|
26 |
"lodash": "^4.17.21",
|
27 |
"log4js": "^6.9.1",
|
28 |
"md5": "^2.3.0",
|
29 |
-
"moment": "^2.
|
30 |
"node-fetch": "^3.3.2",
|
31 |
"node-schedule": "^2.1.1",
|
32 |
-
"node-xlsx": "^0.23.0",
|
33 |
"oicq": "link:lib/modules/oicq",
|
34 |
"pm2": "^5.3.0",
|
35 |
-
"puppeteer": "^21.
|
36 |
-
"redis": "^4.6.
|
37 |
-
"sequelize": "^6.
|
38 |
"sqlite3": "^5.1.6",
|
39 |
-
"ws": "^8.
|
40 |
-
"yaml": "^2.3.
|
41 |
},
|
42 |
"devDependencies": {
|
43 |
-
"eslint": "^8.
|
44 |
"eslint-config-standard": "^17.1.0",
|
45 |
-
"eslint-plugin-import": "^2.
|
46 |
-
"eslint-plugin-n": "^16.
|
47 |
"eslint-plugin-promise": "^6.1.1"
|
48 |
},
|
49 |
"imports": {
|
|
|
1 |
{
|
2 |
"name": "trss-yunzai",
|
3 |
+
"version": "3.1.3",
|
4 |
"author": "TimeRainStarSky, Yoimiya-Kokomi, Le-niao",
|
5 |
"description": "Bot",
|
6 |
"main": "app.js",
|
|
|
13 |
"start": "pm2 start ./config/pm2/pm2.json",
|
14 |
"stop": "pm2 stop ./config/pm2/pm2.json",
|
15 |
"restart": "pm2 restart ./config/pm2/pm2.json",
|
16 |
+
"log": "node ./lib/tools/log.js"
|
17 |
},
|
18 |
"dependencies": {
|
19 |
"art-template": "^4.13.2",
|
20 |
"chalk": "^5.3.0",
|
21 |
"chokidar": "^3.5.3",
|
22 |
"express": "^4.18.2",
|
23 |
+
"file-type": "^18.7.0",
|
24 |
"https-proxy-agent": "7.0.2",
|
25 |
"image-size": "^1.0.2",
|
26 |
"lodash": "^4.17.21",
|
27 |
"log4js": "^6.9.1",
|
28 |
"md5": "^2.3.0",
|
29 |
+
"moment": "^2.30.1",
|
30 |
"node-fetch": "^3.3.2",
|
31 |
"node-schedule": "^2.1.1",
|
|
|
32 |
"oicq": "link:lib/modules/oicq",
|
33 |
"pm2": "^5.3.0",
|
34 |
+
"puppeteer": "^21.6.1",
|
35 |
+
"redis": "^4.6.12",
|
36 |
+
"sequelize": "^6.35.2",
|
37 |
"sqlite3": "^5.1.6",
|
38 |
+
"ws": "^8.16.0",
|
39 |
+
"yaml": "^2.3.4"
|
40 |
},
|
41 |
"devDependencies": {
|
42 |
+
"eslint": "^8.56.0",
|
43 |
"eslint-config-standard": "^17.1.0",
|
44 |
+
"eslint-plugin-import": "^2.29.1",
|
45 |
+
"eslint-plugin-n": "^16.5.0",
|
46 |
"eslint-plugin-promise": "^6.1.1"
|
47 |
},
|
48 |
"imports": {
|
Yunzai/pnpm-lock.yaml
ADDED
The diff for this file is too large to render.
See raw diff
|
|