新增 GSUIDCore、微信 适配器,细节优化
This commit is contained in:
		
							parent
							
								
									c47e5a6519
								
							
						
					
					
						commit
						81d59035be
					
				| 
						 | 
				
			
			@ -1,5 +1,6 @@
 | 
			
		|||
# 3.1.0
 | 
			
		||||
 | 
			
		||||
* 支持协议端:GSUIDCore、微信
 | 
			
		||||
* 重构CK与UID管理逻辑
 | 
			
		||||
    * 支持多UID绑定,可绑定多个UID并进行切换
 | 
			
		||||
    * 支持原神与星铁UID共存,可针对查询命令分配对应UID
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										18
									
								
								README.md
								
								
								
								
							
							
						
						
									
										18
									
								
								README.md
								
								
								
								
							| 
						 | 
				
			
			@ -2,7 +2,7 @@
 | 
			
		|||
 | 
			
		||||
# TRSS-Yunzai
 | 
			
		||||
 | 
			
		||||
Yunzai 应用端,支持多账号,支持协议端:go-cqhttp、ComWeChat、ICQQ、QQ频道、KOOK、Telegram、Discord
 | 
			
		||||
Yunzai 应用端,支持多账号,支持协议端:go-cqhttp、ComWeChat、GSUIDCore、ICQQ、QQ频道、微信、KOOK、Telegram、Discord
 | 
			
		||||
 | 
			
		||||
[](https://github.com/TimeRainStarSky/Yunzai)
 | 
			
		||||
[](../../stargazers)
 | 
			
		||||
| 
						 | 
				
			
			@ -110,6 +110,16 @@ websocket_url = ["ws://localhost:2536/ComWeChat"]
 | 
			
		|||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details><summary>GSUIDCore</summary>
 | 
			
		||||
 | 
			
		||||
下载运行 [GenshinUID 插件](http://docs.gsuid.gbots.work/#/AdapterList),GSUIDCore 连接地址 修改为:
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
ws://localhost:2536/GSUIDCore
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details><summary>ICQQ</summary>
 | 
			
		||||
 | 
			
		||||
[TRSS-Yunzai ICQQ Plugin](../../../Yunzai-ICQQ-Plugin)
 | 
			
		||||
| 
						 | 
				
			
			@ -122,6 +132,12 @@ websocket_url = ["ws://localhost:2536/ComWeChat"]
 | 
			
		|||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details><summary>微信</summary>
 | 
			
		||||
 | 
			
		||||
[TRSS-Yunzai WeChat Plugin](../../../Yunzai-WeChat-Plugin)
 | 
			
		||||
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
<details><summary>KOOK</summary>
 | 
			
		||||
 | 
			
		||||
[TRSS-Yunzai KOOK Plugin](../../../Yunzai-KOOK-Plugin)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								lib/bot.js
								
								
								
								
							
							
						
						
									
										24
									
								
								lib/bot.js
								
								
								
								
							| 
						 | 
				
			
			@ -23,21 +23,16 @@ export default class Yunzai extends EventEmitter {
 | 
			
		|||
    this.emit("online", this)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  serverRequest(req) {
 | 
			
		||||
    logger.info(`${logger.blue(`[${req.ip}]`)} HTTP ${req.method} 请求:${req.url} ${JSON.stringify(req.rawHeaders)}`)
 | 
			
		||||
    req.res.redirect("https://github.com/TimeRainStarSky/Yunzai")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  serverLoad() {
 | 
			
		||||
    this.server.get("*", this.serverRequest)
 | 
			
		||||
    this.server.post("*", this.serverRequest)
 | 
			
		||||
    this.server.all("*", req => {
 | 
			
		||||
      logger.info(`${logger.blue(`[${req.ip}]`)} HTTP ${req.method} 请求:${req.url} ${JSON.stringify(req.rawHeaders)}`)
 | 
			
		||||
      req.res.redirect("https://github.com/TimeRainStarSky/Yunzai")
 | 
			
		||||
    })
 | 
			
		||||
    this.server = http.createServer(this.server)
 | 
			
		||||
 | 
			
		||||
    this.server.on("upgrade", (req, socket, head) => {
 | 
			
		||||
      for (const i of Object.keys(this.wss))
 | 
			
		||||
        if (req.url == `/${i}`)
 | 
			
		||||
          return this.wss[i].handleUpgrade(req, socket, head, conn =>
 | 
			
		||||
            this.wss[i].emit("connection", conn, req))
 | 
			
		||||
      const wss = this.wss[req.url.split("/")[1]]
 | 
			
		||||
      if (wss) wss.handleUpgrade(req, socket, head, conn => wss.emit("connection", conn, req))
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    this.server.listen(cfg.bot.port, () => {
 | 
			
		||||
| 
						 | 
				
			
			@ -197,4 +192,11 @@ export default class Yunzai extends EventEmitter {
 | 
			
		|||
    msg.replace = () => msg
 | 
			
		||||
    return { type: "node", data: msg }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendForwardMsg(send, msg) {
 | 
			
		||||
    const messages = []
 | 
			
		||||
    for (const i of msg)
 | 
			
		||||
      messages.push(await send(i.message))
 | 
			
		||||
    return messages
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -11,16 +11,15 @@ process.env.TZ = 'Asia/Shanghai'
 | 
			
		|||
 | 
			
		||||
/** 捕获未处理的Promise错误 */
 | 
			
		||||
process.on('unhandledRejection', (error, promise) => {
 | 
			
		||||
  let err = error
 | 
			
		||||
  if (logger) {
 | 
			
		||||
    logger.error(err)
 | 
			
		||||
    logger.error(error)
 | 
			
		||||
  } else {
 | 
			
		||||
    console.log(err)
 | 
			
		||||
    console.log(error)
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
/** 退出事件 */
 | 
			
		||||
process.on('exit', async (code) => {
 | 
			
		||||
process.on('exit', async code => {
 | 
			
		||||
  if (typeof redis != 'undefined' && typeof test == 'undefined')
 | 
			
		||||
    await redis.save()
 | 
			
		||||
  logger.mark(logger.magenta('TRSS-Yunzai 已停止运行'))
 | 
			
		||||
| 
						 | 
				
			
			@ -29,7 +28,7 @@ process.on('exit', async (code) => {
 | 
			
		|||
await checkInit()
 | 
			
		||||
 | 
			
		||||
/** 初始化事件 */
 | 
			
		||||
async function checkInit () {
 | 
			
		||||
async function checkInit() {
 | 
			
		||||
  /** 日志设置 */
 | 
			
		||||
  setLog()
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,8 +16,7 @@ Bot.adapter.push(new class stdinAdapter {
 | 
			
		|||
      return Buffer.from(await (await fetch(file)).arrayBuffer())
 | 
			
		||||
    else if (fs.existsSync(file))
 | 
			
		||||
      return Buffer.from(fs.readFileSync(file))
 | 
			
		||||
    else
 | 
			
		||||
      return file
 | 
			
		||||
    return file
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async fileType(data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -69,7 +68,7 @@ Bot.adapter.push(new class stdinAdapter {
 | 
			
		|||
        case "at":
 | 
			
		||||
          break
 | 
			
		||||
        case "node":
 | 
			
		||||
          this.sendForwardMsg(i.data)
 | 
			
		||||
          Bot.sendForwardMsg(msg => this.sendMsg(msg), i.data)
 | 
			
		||||
          break
 | 
			
		||||
        default:
 | 
			
		||||
          i = JSON.stringify(i)
 | 
			
		||||
| 
						 | 
				
			
			@ -85,13 +84,6 @@ Bot.adapter.push(new class stdinAdapter {
 | 
			
		|||
    logger.info(`${logger.blue(`[${this.id}]`)} 撤回消息:${message_id}`)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  sendForwardMsg(msg) {
 | 
			
		||||
    const messages = []
 | 
			
		||||
    for (const i of msg)
 | 
			
		||||
      messages.push(this.sendMsg(i.message))
 | 
			
		||||
    return messages
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendFile(file, name = path.basename(file)) {
 | 
			
		||||
    const buffer = await this.makeBuffer(file)
 | 
			
		||||
    if (!Buffer.isBuffer(buffer)) {
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +101,7 @@ Bot.adapter.push(new class stdinAdapter {
 | 
			
		|||
      sendMsg: msg => this.sendMsg(msg),
 | 
			
		||||
      recallMsg: message_id => this.recallMsg(message_id),
 | 
			
		||||
      makeForwardMsg: Bot.makeForwardMsg,
 | 
			
		||||
      sendForwardMsg: msg => this.sendForwardMsg(msg),
 | 
			
		||||
      sendForwardMsg: msg => Bot.sendForwardMsg(msg => this.sendMsg(msg), msg),
 | 
			
		||||
      sendFile: (file, name) => this.sendFile(file, name),
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			@ -140,8 +132,8 @@ Bot.adapter.push(new class stdinAdapter {
 | 
			
		|||
      version: { id: this.id, name: this.name },
 | 
			
		||||
      pickFriend: () => this.pickFriend(),
 | 
			
		||||
      pickUser: () => this.pickFriend(),
 | 
			
		||||
      pickGroup: () => this.pickFriend(),
 | 
			
		||||
      pickMember: () => this.pickFriend(),
 | 
			
		||||
      pickGroup: () => this.pickFriend(),
 | 
			
		||||
 | 
			
		||||
      fl: new Map().set(this.id, {
 | 
			
		||||
        user_id: this.id,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,7 @@
 | 
			
		|||
    "yaml": "^2.3.1"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "eslint": "^8.43.0",
 | 
			
		||||
    "eslint": "^8.44.0",
 | 
			
		||||
    "eslint-config-standard": "^17.1.0",
 | 
			
		||||
    "eslint-plugin-import": "^2.27.5",
 | 
			
		||||
    "eslint-plugin-n": "^16.0.1",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,6 +7,7 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
  constructor() {
 | 
			
		||||
    this.id = "WeChat"
 | 
			
		||||
    this.name = "ComWeChat"
 | 
			
		||||
    this.path = this.name
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toStr(data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -21,6 +22,7 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
        else
 | 
			
		||||
          return JSON.stringify(data)
 | 
			
		||||
    }
 | 
			
		||||
    return data
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  makeLog(msg) {
 | 
			
		||||
| 
						 | 
				
			
			@ -37,8 +39,23 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
        resolve({ ...data, ...data.data })))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uploadFile(data, file, name = randomUUID()) {
 | 
			
		||||
    const opts = { name }
 | 
			
		||||
  async fileName(file) {
 | 
			
		||||
    try {
 | 
			
		||||
      if (file.match(/^base64:\/\//)) {
 | 
			
		||||
        const buffer = Buffer.from(file.replace(/^base64:\/\//, ""), "base64")
 | 
			
		||||
        const type = await fileTypeFromBuffer(buffer)
 | 
			
		||||
        return `${Date.now()}.${type.ext}`
 | 
			
		||||
      } else {
 | 
			
		||||
        return path.basename(file)
 | 
			
		||||
      }
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      logger.error(`文件类型检测错误:${logger.red(err)}`)
 | 
			
		||||
    }
 | 
			
		||||
    return false
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async uploadFile(data, file, name) {
 | 
			
		||||
    const opts = { name: name || await this.fileName(file) || randomUUID() }
 | 
			
		||||
 | 
			
		||||
    if (file.match(/^https?:\/\//)) {
 | 
			
		||||
      opts.type = "url"
 | 
			
		||||
| 
						 | 
				
			
			@ -54,6 +71,7 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
      opts.path = file
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    logger.info(`${logger.blue(`[${data.self_id}]`)} 上传文件:${this.makeLog(opts)}`)
 | 
			
		||||
    return data.sendApi("upload_file", opts)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -68,53 +86,61 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
        i = { type: i.type, data: { ...i, type: undefined }}
 | 
			
		||||
      if (i.data.file)
 | 
			
		||||
        i.data = { file_id: (await this.uploadFile(data, i.data.file)).file_id }
 | 
			
		||||
 | 
			
		||||
      switch (i.type) {
 | 
			
		||||
        case "text":
 | 
			
		||||
          break
 | 
			
		||||
        case "image":
 | 
			
		||||
          break
 | 
			
		||||
        case "record":
 | 
			
		||||
          i.type = "file"
 | 
			
		||||
          break
 | 
			
		||||
        case "video":
 | 
			
		||||
          i.type = "file"
 | 
			
		||||
          break
 | 
			
		||||
        case "at":
 | 
			
		||||
          if (i.data.qq == "all")
 | 
			
		||||
            msgs.push({ type: "mention_all", data: {}})
 | 
			
		||||
            i = { type: "mention_all", data: {}}
 | 
			
		||||
          else
 | 
			
		||||
            msgs.push({ type: "mention", data: { user_id: i.data.qq }})
 | 
			
		||||
            i = { type: "mention", data: { user_id: i.data.qq }}
 | 
			
		||||
          break
 | 
			
		||||
        case "reply":
 | 
			
		||||
          i = { type: "text", data: { text: `回复:${i.data.id}\n` }}
 | 
			
		||||
          break
 | 
			
		||||
        default:
 | 
			
		||||
          msgs.push(i)
 | 
			
		||||
          i = { type: "text", data: { text: JSON.stringify(i) }}
 | 
			
		||||
      }
 | 
			
		||||
      msgs.push(i)
 | 
			
		||||
    }
 | 
			
		||||
    return msgs
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendFriendMsg(data, msg) {
 | 
			
		||||
    if (msg?.type == "node")
 | 
			
		||||
      return this.sendForwardMsg(msg => this.sendFriendMsg(data, msg), msg.data)
 | 
			
		||||
      return Bot.sendForwardMsg(msg => this.sendFriendMsg(data, msg), msg.data)
 | 
			
		||||
 | 
			
		||||
    logger.info(`${logger.blue(`[${data.self_id}]`)} 发送好友消息:[${data.user_id}] ${this.makeLog(msg)}`)
 | 
			
		||||
    const message = await this.makeMsg(data, msg)
 | 
			
		||||
    logger.info(`${logger.blue(`[${data.self_id}]`)} 发送好友消息:[${data.user_id}] ${this.makeLog(message)}`)
 | 
			
		||||
    return data.sendApi("send_message", {
 | 
			
		||||
      detail_type: "private",
 | 
			
		||||
      user_id: data.user_id,
 | 
			
		||||
      message: await this.makeMsg(data, msg),
 | 
			
		||||
      message,
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendGroupMsg(data, msg) {
 | 
			
		||||
    if (msg?.type == "node")
 | 
			
		||||
      return this.sendForwardMsg(msg => this.sendGroupMsg(data, msg), msg.data)
 | 
			
		||||
      return Bot.sendForwardMsg(msg => this.sendGroupMsg(data, msg), msg.data)
 | 
			
		||||
 | 
			
		||||
    logger.info(`${logger.blue(`[${data.self_id}]`)} 发送群消息:[${data.group_id}] ${this.makeLog(msg)}`)
 | 
			
		||||
    const message = await this.makeMsg(data, msg)
 | 
			
		||||
    logger.info(`${logger.blue(`[${data.self_id}]`)} 发送群消息:[${data.group_id}] ${this.makeLog(message)}`)
 | 
			
		||||
    return data.sendApi("send_message", {
 | 
			
		||||
      detail_type: "group",
 | 
			
		||||
      group_id: data.group_id,
 | 
			
		||||
      message: await this.makeMsg(data, msg),
 | 
			
		||||
      message,
 | 
			
		||||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendForwardMsg(send, msg) {
 | 
			
		||||
    const messages = []
 | 
			
		||||
    for (const i of msg)
 | 
			
		||||
      messages.push(await send(i.message))
 | 
			
		||||
    return messages
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async getFriendArray(data) {
 | 
			
		||||
    const array = []
 | 
			
		||||
    for (const i of (await data.sendApi("get_friend_list")).data)
 | 
			
		||||
| 
						 | 
				
			
			@ -196,7 +222,7 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
    })
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendFile(data, send, file, name = path.basename(file)) {
 | 
			
		||||
  async sendFile(data, send, file, name) {
 | 
			
		||||
    logger.info(`${logger.blue(`[${data.self_id}]`)} 发送文件:${name}(${file})`)
 | 
			
		||||
    return send(segment.custom("file", {
 | 
			
		||||
      file_id: (await this.uploadFile(data, file, name)).file_id
 | 
			
		||||
| 
						 | 
				
			
			@ -214,7 +240,7 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
      sendMsg: msg => this.sendFriendMsg(i, msg),
 | 
			
		||||
      recallMsg: () => false,
 | 
			
		||||
      makeForwardMsg: Bot.makeForwardMsg,
 | 
			
		||||
      sendForwardMsg: msg => this.sendForwardMsg(msg => this.sendFriendMsg(i, msg), msg),
 | 
			
		||||
      sendForwardMsg: msg => Bot.sendForwardMsg(msg => this.sendFriendMsg(i, msg), msg),
 | 
			
		||||
      sendFile: (file, name) => this.sendFile(i, msg => this.sendFriendMsg(i, msg), file, name),
 | 
			
		||||
      getInfo: () => this.getFriendInfo(i),
 | 
			
		||||
      getAvatarUrl: async () => (await this.getFriendInfo(i))["wx.avatar"],
 | 
			
		||||
| 
						 | 
				
			
			@ -247,7 +273,7 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
      sendMsg: msg => this.sendGroupMsg(i, msg),
 | 
			
		||||
      recallMsg: () => false,
 | 
			
		||||
      makeForwardMsg: Bot.makeForwardMsg,
 | 
			
		||||
      sendForwardMsg: msg => this.sendForwardMsg(msg => this.sendGroupMsg(i, msg), msg),
 | 
			
		||||
      sendForwardMsg: msg => Bot.sendForwardMsg(msg => this.sendGroupMsg(i, msg), msg),
 | 
			
		||||
      sendFile: (file, name) => this.sendFile(i, msg => this.sendGroupMsg(i, msg), file, name),
 | 
			
		||||
      getInfo: () => this.getGroupInfo(i),
 | 
			
		||||
      getAvatarUrl: async () => (await this.getGroupInfo(i))["wx.avatar"],
 | 
			
		||||
| 
						 | 
				
			
			@ -263,9 +289,11 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
      data.self_id = bot.self.user_id
 | 
			
		||||
 | 
			
		||||
    Bot[data.self_id] = {
 | 
			
		||||
      adapter: this,
 | 
			
		||||
      sendApi: data.sendApi,
 | 
			
		||||
      stat: { ...data.status, start_time: data.time },
 | 
			
		||||
 | 
			
		||||
      pickUser: user_id => this.pickFriend(data, user_id),
 | 
			
		||||
      pickFriend: user_id => this.pickFriend(data, user_id),
 | 
			
		||||
 | 
			
		||||
      getFriendArray: () => this.getFriendArray(data),
 | 
			
		||||
| 
						 | 
				
			
			@ -279,7 +307,6 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
      getGroupList: () => this.getGroupList(data),
 | 
			
		||||
      getGroupMap: () => this.getGroupMap(data),
 | 
			
		||||
    }
 | 
			
		||||
    Bot[data.self_id].pickUser = Bot[data.self_id].pickFriend
 | 
			
		||||
 | 
			
		||||
    Bot[data.self_id].info = (await data.sendApi("get_self_info")).data
 | 
			
		||||
    Bot[data.self_id].uin = Bot[data.self_id].info.user_id
 | 
			
		||||
| 
						 | 
				
			
			@ -411,8 +438,8 @@ Bot.adapter.push(new class ComWeChatAdapter {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  load() {
 | 
			
		||||
    Bot.wss[this.name] = new WebSocketServer({ noServer: true })
 | 
			
		||||
    Bot.wss[this.name].on("connection", ws => {
 | 
			
		||||
    Bot.wss[this.path] = new WebSocketServer({ noServer: true })
 | 
			
		||||
    Bot.wss[this.path].on("connection", ws => {
 | 
			
		||||
      ws.on("error", logger.error)
 | 
			
		||||
      ws.on("message", data => this.message(data, ws))
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,265 @@
 | 
			
		|||
import { WebSocketServer } from "ws"
 | 
			
		||||
import { randomUUID } from "crypto"
 | 
			
		||||
import path from "node:path"
 | 
			
		||||
import fs from "node:fs"
 | 
			
		||||
 | 
			
		||||
Bot.adapter.push(new class GSUIDCoreAdapter {
 | 
			
		||||
  constructor() {
 | 
			
		||||
    this.id = "GSUIDCore"
 | 
			
		||||
    this.name = "早柚核心"
 | 
			
		||||
    this.path = "GSUIDCore"
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toStr(data) {
 | 
			
		||||
    switch (typeof data) {
 | 
			
		||||
      case "string":
 | 
			
		||||
        return data
 | 
			
		||||
      case "number":
 | 
			
		||||
        return String(data)
 | 
			
		||||
      case "object":
 | 
			
		||||
        if (Buffer.isBuffer(data))
 | 
			
		||||
          return Buffer.from(data, "utf8").toString()
 | 
			
		||||
        else
 | 
			
		||||
          return JSON.stringify(data)
 | 
			
		||||
    }
 | 
			
		||||
    return data
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  makeLog(msg) {
 | 
			
		||||
    return this.toStr(msg).replace(/("type":"(image|file)","data":").*?(")/g, "$1...$3")
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async makeBase64(file) {
 | 
			
		||||
    if (file.match(/^base64:\/\//))
 | 
			
		||||
      return file.replace(/^base64:\/\//, "")
 | 
			
		||||
    else if (file.match(/^https?:\/\//))
 | 
			
		||||
      return Buffer.from(await (await fetch(file)).arrayBuffer()).toString("base64")
 | 
			
		||||
    return file
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async makeMsg(msg) {
 | 
			
		||||
    if (!Array.isArray(msg))
 | 
			
		||||
      msg = [msg]
 | 
			
		||||
    const msgs = []
 | 
			
		||||
    for (let i of msg) {
 | 
			
		||||
      if (typeof i != "object")
 | 
			
		||||
        i = { type: "text", data: { text: i }}
 | 
			
		||||
      else if (!i.data)
 | 
			
		||||
        i = { type: i.type, data: { ...i, type: undefined }}
 | 
			
		||||
      if (i.data.file)
 | 
			
		||||
        i.data = await this.makeBase64(i.data.file)
 | 
			
		||||
 | 
			
		||||
      switch (i.type) {
 | 
			
		||||
        case "text":
 | 
			
		||||
          i.data = i.data.text
 | 
			
		||||
          break
 | 
			
		||||
        case "image":
 | 
			
		||||
          break
 | 
			
		||||
        case "file":
 | 
			
		||||
          break
 | 
			
		||||
        case "at":
 | 
			
		||||
          i.data = i.data.qq
 | 
			
		||||
          break
 | 
			
		||||
        case "reply":
 | 
			
		||||
          i.data = i.data.id
 | 
			
		||||
          break
 | 
			
		||||
        case "record":
 | 
			
		||||
          i.type = "file"
 | 
			
		||||
          break
 | 
			
		||||
        case "video":
 | 
			
		||||
          i.type = "file"
 | 
			
		||||
          break
 | 
			
		||||
        case "node":
 | 
			
		||||
          for (const n in i.data)
 | 
			
		||||
            i.data[n] = await this.makeMsg(i.data[n])
 | 
			
		||||
        default:
 | 
			
		||||
          i = { type: "text", data: JSON.stringify(i) }
 | 
			
		||||
      }
 | 
			
		||||
      msgs.push(i)
 | 
			
		||||
    }
 | 
			
		||||
    return msgs
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendFriendMsg(data, msg) {
 | 
			
		||||
    const content = await this.makeMsg(msg)
 | 
			
		||||
    logger.info(`${logger.blue(`[${data.self_id}]`)} 发送好友消息:[${data.user_id}] ${this.makeLog(content)}`)
 | 
			
		||||
    return data.bot.send(JSON.stringify({
 | 
			
		||||
      bot_id: data.bot.bot_id,
 | 
			
		||||
      bot_self_id: data.bot.bot_self_id,
 | 
			
		||||
      target_type: "direct",
 | 
			
		||||
      target_id: data.user_id,
 | 
			
		||||
      content,
 | 
			
		||||
    }))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async sendGroupMsg(data, msg) {
 | 
			
		||||
    data.group_id = data.group_id.split("-")
 | 
			
		||||
    const content = await this.makeMsg(msg)
 | 
			
		||||
    logger.info(`${logger.blue(`[${data.self_id}]`)} 发送群消息:[${data.group_id}] ${this.makeLog(content)}`)
 | 
			
		||||
    return data.bot.send(JSON.stringify({
 | 
			
		||||
      bot_id: data.bot.bot_id,
 | 
			
		||||
      bot_self_id: data.bot.bot_self_id,
 | 
			
		||||
      target_type: data.group_id[0],
 | 
			
		||||
      target_id: data.group_id[1],
 | 
			
		||||
      content,
 | 
			
		||||
    }))
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pickFriend(id, user_id) {
 | 
			
		||||
    const i = {
 | 
			
		||||
      ...Bot[id].fl.get(user_id),
 | 
			
		||||
      self_id: id,
 | 
			
		||||
      bot: Bot[id],
 | 
			
		||||
      user_id: user_id.replace(/^gc_/, ""),
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
      ...i,
 | 
			
		||||
      sendMsg: msg => this.sendFriendMsg(i, msg),
 | 
			
		||||
      recallMsg: () => false,
 | 
			
		||||
      makeForwardMsg: Bot.makeForwardMsg,
 | 
			
		||||
      sendForwardMsg: msg => Bot.sendForwardMsg(msg => this.sendFriendMsg(i, msg), msg),
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pickMember(id, group_id, user_id) {
 | 
			
		||||
    const i = {
 | 
			
		||||
      ...Bot[id].fl.get(user_id),
 | 
			
		||||
      self_id: id,
 | 
			
		||||
      bot: Bot[id],
 | 
			
		||||
      group_id: group_id.replace(/^gc_/, ""),
 | 
			
		||||
      user_id: user_id.replace(/^gc_/, ""),
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
      ...this.pickFriend(id, user_id),
 | 
			
		||||
      ...i,
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  pickGroup(id, group_id) {
 | 
			
		||||
    const i = {
 | 
			
		||||
      ...Bot[id].gl.get(group_id),
 | 
			
		||||
      self_id: id,
 | 
			
		||||
      bot: Bot[id],
 | 
			
		||||
      group_id: group_id.replace(/^gc_/, ""),
 | 
			
		||||
    }
 | 
			
		||||
    return {
 | 
			
		||||
      ...i,
 | 
			
		||||
      sendMsg: msg => this.sendGroupMsg(i, msg),
 | 
			
		||||
      recallMsg: message_id => this.recallMsg(i, message_id => i.bot.API.message.delete(message_id), message_id),
 | 
			
		||||
      makeForwardMsg: Bot.makeForwardMsg,
 | 
			
		||||
      sendForwardMsg: msg => Bot.sendForwardMsg(msg => this.sendGroupMsg(i, msg), msg),
 | 
			
		||||
      pickMember: user_id => this.pickMember(id, group_id, user_id),
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  makeBot(data, send) {
 | 
			
		||||
    Bot[data.self_id] = {
 | 
			
		||||
      adapter: this,
 | 
			
		||||
      send,
 | 
			
		||||
      uin: data.self_id,
 | 
			
		||||
      bot_id: data.bot_id,
 | 
			
		||||
      bot_self_id: data.bot_self_id,
 | 
			
		||||
      stat: { start_time: Date.now()/1000 },
 | 
			
		||||
      version: {
 | 
			
		||||
        id: this.id,
 | 
			
		||||
        name: this.name,
 | 
			
		||||
      },
 | 
			
		||||
      pickFriend: user_id => this.pickFriend(data.self_id, user_id),
 | 
			
		||||
      pickMember: (group_id, user_id) => this.pickMember(data.self_id, group_id, user_id),
 | 
			
		||||
      pickGroup: group_id => this.pickGroup(data.self_id, group_id),
 | 
			
		||||
      fl: new Map(),
 | 
			
		||||
      gl: new Map(),
 | 
			
		||||
    }
 | 
			
		||||
    Bot[data.self_id].pickUser = Bot[data.self_id].pickFriend
 | 
			
		||||
 | 
			
		||||
    logger.mark(`${logger.blue(`[${data.self_id}]`)} ${this.name}(${this.id}) 已连接`)
 | 
			
		||||
    Bot.emit(`connect.${data.self_id}`, Bot[data.self_id])
 | 
			
		||||
    Bot.emit(`connect`, Bot[data.self_id])
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  message(data, ws) {
 | 
			
		||||
    try {
 | 
			
		||||
      data = JSON.parse(data)
 | 
			
		||||
    } catch (err) {
 | 
			
		||||
      return logger.error(`解码数据失败:${logger.red(err)}`)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    data.self_id = `gc_${data.bot_self_id}`
 | 
			
		||||
    if (Bot[data.self_id])
 | 
			
		||||
      Bot[data.self_id].send = ws.send
 | 
			
		||||
    else
 | 
			
		||||
      this.makeBot(data, ws.send)
 | 
			
		||||
    data.bot = Bot[data.self_id]
 | 
			
		||||
 | 
			
		||||
    data.post_type = "message"
 | 
			
		||||
    data.message_id = data.msg_id
 | 
			
		||||
    data.user_id = `gc_${data.user_id}`
 | 
			
		||||
    data.sender = {
 | 
			
		||||
      user_id: data.user_id,
 | 
			
		||||
      user_pm: data.user_pm,
 | 
			
		||||
    }
 | 
			
		||||
    if (!data.bot.fl.has(data.user_id))
 | 
			
		||||
      data.bot.fl.set(data.user_id, data.sender)
 | 
			
		||||
 | 
			
		||||
    data.message = []
 | 
			
		||||
    data.raw_message = ""
 | 
			
		||||
    for (const i of data.content) {
 | 
			
		||||
      switch (i.type) {
 | 
			
		||||
        case "text":
 | 
			
		||||
          data.message.push({ type: "text", text: i.data })
 | 
			
		||||
          data.raw_message += i.data
 | 
			
		||||
          break
 | 
			
		||||
        case "image":
 | 
			
		||||
          data.message.push({ type: "image", url: i.data })
 | 
			
		||||
          data.raw_message += `[图片:${i.data}]`
 | 
			
		||||
          break
 | 
			
		||||
        case "file":
 | 
			
		||||
          data.message.push({ type: "file", url: i.data })
 | 
			
		||||
          data.raw_message += `[文件:${i.data}]`
 | 
			
		||||
          break
 | 
			
		||||
        case "at":
 | 
			
		||||
          data.message.push({ type: "at", qq: i.data })
 | 
			
		||||
          data.raw_message += `[提及:${i.data}]`
 | 
			
		||||
          break
 | 
			
		||||
        case "reply":
 | 
			
		||||
          data.message.push({ type: "reply", id: i.data })
 | 
			
		||||
          data.raw_message += `[回复:${i.data}]`
 | 
			
		||||
          break
 | 
			
		||||
        case "node":
 | 
			
		||||
          data.message.push({ type: "node", data: i.data })
 | 
			
		||||
          data.raw_message += `[合并转发:${JSON.stringify(i.data)}]`
 | 
			
		||||
          break
 | 
			
		||||
        default:
 | 
			
		||||
          data.message.push(i)
 | 
			
		||||
          data.raw_message += JSON.stringify(i)
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (data.user_type == "direct") {
 | 
			
		||||
      data.message_type = "private"
 | 
			
		||||
      logger.info(`${logger.blue(`[${data.self_id}]`)} 好友消息:[${data.user_id}] ${data.raw_message}`)
 | 
			
		||||
      data.friend = data.bot.pickFriend(data.user_id)
 | 
			
		||||
    } else {
 | 
			
		||||
      data.message_type = "group"
 | 
			
		||||
      data.group_id = `gc_${data.user_type}-${data.group_id}`
 | 
			
		||||
      if (!data.bot.gl.has(data.group_id))
 | 
			
		||||
        data.bot.gl.set(data.group_id, { group_id: data.group_id })
 | 
			
		||||
      logger.info(`${logger.blue(`[${data.self_id}]`)} 群消息:[${data.group_id}, ${data.user_id}] ${data.raw_message}`)
 | 
			
		||||
      data.friend = data.bot.pickFriend(data.user_id)
 | 
			
		||||
      data.group = data.bot.pickGroup(data.group_id)
 | 
			
		||||
      data.member = data.group.pickMember(data.user_id)
 | 
			
		||||
    }
 | 
			
		||||
    console.log(data)
 | 
			
		||||
    Bot.emit(`${data.post_type}.${data.message_type}`, data)
 | 
			
		||||
    Bot.emit(`${data.post_type}`, data)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  load() {
 | 
			
		||||
    Bot.wss[this.path] = new WebSocketServer({ noServer: true })
 | 
			
		||||
    Bot.wss[this.path].on("connection", ws => {
 | 
			
		||||
      ws.on("error", logger.error)
 | 
			
		||||
      ws.on("message", data => this.message(data, ws))
 | 
			
		||||
    })
 | 
			
		||||
    return true
 | 
			
		||||
  }
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ Bot.adapter.push(new class gocqhttpAdapter {
 | 
			
		|||
  constructor() {
 | 
			
		||||
    this.id = "QQ"
 | 
			
		||||
    this.name = "go-cqhttp"
 | 
			
		||||
    this.path = this.name
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  toStr(data) {
 | 
			
		||||
| 
						 | 
				
			
			@ -20,6 +21,7 @@ Bot.adapter.push(new class gocqhttpAdapter {
 | 
			
		|||
        else
 | 
			
		||||
          return JSON.stringify(data)
 | 
			
		||||
    }
 | 
			
		||||
    return data
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  makeLog(msg) {
 | 
			
		||||
| 
						 | 
				
			
			@ -525,6 +527,7 @@ Bot.adapter.push(new class gocqhttpAdapter {
 | 
			
		|||
 | 
			
		||||
  async connect(data) {
 | 
			
		||||
    Bot[data.self_id] = {
 | 
			
		||||
      adapter: this,
 | 
			
		||||
      sendApi: data.sendApi,
 | 
			
		||||
      stat: { start_time: data.time },
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -532,6 +535,7 @@ Bot.adapter.push(new class gocqhttpAdapter {
 | 
			
		|||
      recallMsg: message_id => this.recallMsg(data, message_id),
 | 
			
		||||
      getForwardMsg: message_id => this.getForwardMsg(data, message_id),
 | 
			
		||||
 | 
			
		||||
      pickUser: user_id => this.pickFriend(data, user_id),
 | 
			
		||||
      pickFriend: user_id => this.pickFriend(data, user_id),
 | 
			
		||||
 | 
			
		||||
      getFriendArray: () => this.getFriendArray(data),
 | 
			
		||||
| 
						 | 
				
			
			@ -545,7 +549,6 @@ Bot.adapter.push(new class gocqhttpAdapter {
 | 
			
		|||
      getGroupList: () => this.getGroupList(data),
 | 
			
		||||
      getGroupMap: () => this.getGroupMap(data),
 | 
			
		||||
    }
 | 
			
		||||
    Bot[data.self_id].pickUser = Bot[data.self_id].pickFriend
 | 
			
		||||
 | 
			
		||||
    Bot[data.self_id].info = (await data.sendApi("get_login_info")).data
 | 
			
		||||
    Bot[data.self_id].uin = Bot[data.self_id].info.user_id
 | 
			
		||||
| 
						 | 
				
			
			@ -566,9 +569,8 @@ Bot.adapter.push(new class gocqhttpAdapter {
 | 
			
		|||
    Bot[data.self_id].version = (await data.sendApi("get_version_info")).data
 | 
			
		||||
    Bot[data.self_id].version = {
 | 
			
		||||
      ...Bot[data.self_id].version,
 | 
			
		||||
      impl: Bot[data.self_id].version.app_name,
 | 
			
		||||
      version: Bot[data.self_id].version.app_version,
 | 
			
		||||
      onebot_version: Bot[data.self_id].version.protocol_version,
 | 
			
		||||
      id: this.id,
 | 
			
		||||
      name: this.name,
 | 
			
		||||
    }
 | 
			
		||||
    Bot[data.self_id].status = Bot[data.self_id].version.protocol_name
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -829,8 +831,8 @@ Bot.adapter.push(new class gocqhttpAdapter {
 | 
			
		|||
  }
 | 
			
		||||
 | 
			
		||||
  load() {
 | 
			
		||||
    Bot.wss[this.name] = new WebSocketServer({ noServer: true })
 | 
			
		||||
    Bot.wss[this.name].on("connection", ws => {
 | 
			
		||||
    Bot.wss[this.path] = new WebSocketServer({ noServer: true })
 | 
			
		||||
    Bot.wss[this.path].on("connection", ws => {
 | 
			
		||||
      ws.on("error", logger.error)
 | 
			
		||||
      ws.on("message", data => this.message(data, ws))
 | 
			
		||||
    })
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -16,6 +16,7 @@ const list = {
 | 
			
		|||
  "Telegram-Plugin"   :"https://gitee.com/TimeRainStarSky/Yunzai-Telegram-Plugin",
 | 
			
		||||
  "Discord-Plugin"    :"https://gitee.com/TimeRainStarSky/Yunzai-Discord-Plugin",
 | 
			
		||||
  "QQGuild-Plugin"    :"https://gitee.com/TimeRainStarSky/Yunzai-QQGuild-Plugin",
 | 
			
		||||
  "WeChat-Plugin"     :"https://gitee.com/TimeRainStarSky/Yunzai-WeChat-Plugin",
 | 
			
		||||
  "ICQQ-Plugin"       :"https://gitee.com/TimeRainStarSky/Yunzai-ICQQ-Plugin",
 | 
			
		||||
  "KOOK-Plugin"       :"https://gitee.com/TimeRainStarSky/Yunzai-KOOK-Plugin",
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue