【教程】用 Node.js 在 Nodeloc 编写机器人

本教程将指导您安装和认识 Nodejs ,并部署机器人。


让我们从认识 NodeJS 开始,Node.js 是一个免费、开源、跨平台的 JavaScript 运行时环境 它允许开发人员创建服务器、Web 应用程序、命令行工具和脚本。

可以从这里下载 Nodejs: Node.js — Download Node.js®

选择自己的系统配置,然后复制命令并执行


安装我自己写的两个轮子:

  • NoHope NodeLoc Session 管理
  • Message Bus Client 长轮询客户端

这里是一个完整的项目文件,包括了上面两个轮子以及一个示范代码
nlbot.zip (5.8 KB)

下载后请解压,然后你会看见三个文件

  • chat.js 示范文件
  • message-bus-client.js 轮子
  • nohope_nodeloc.js 轮子 免责声明:这不是内涵 Nodeloc 无望(而是这个项目),我最近的项目命名风格都很独特

然后安装 node-fetch 依赖库 1.5.2 版本

npm i [email protected]

之后我们编辑 chat.js 文件内容,转到第 63 行,设置自己的用户名和密码,然后保存

最后我们打开控制台执行 node chat.js ,你应该会看见下面内容

正在导入库
正在启动 NoHope
正在启动 MsgBus
就绪

这说明你成功启动了服务!试试打开论坛的吹水群,发送 签到 ,此时你会发现自己反应了 :japanese_prohibited_button:

image

测试发现正常后,先按 Ctrl + C 终止脚本,然后安装 pm2

npm i pm2

之后我们使用 pm2 start chat 就可以把脚本放到后台运行,之后就可以美美哒关掉 SSH 睡觉去了~

然后隔天就发现bot不工作了


写完才发现跑题了,题目是 【教程】用 Node.js 在 Nodeloc 编写机器人 而不是 【教程】部署一个在吹水群遇到有人发 签到 就自动🈲的机器人

那我随便写点那两轮子的教程吧,其实就算我写了那两轮子,实际上编写机器人还是有点复杂的,而且石山(

NoHope NodeLoc

const NoHope = require('./nohope_nodeloc');
const client = new NoHope({
  baseUrl: 'https://nodeloc.cc', // 要登录的论坛
  // forceIP: 'xx.xxx.xxx.xx', // SNI直接连接源站用的,你用不到,用于跳cf盾
  login: {
    username: 'James', // 你的账号
    password: 'ilove4n0n4me' // 你的密码
  }
});

async function main() {
  await client.init(); // 初始化客户端
  /* 现在你可以用 client._fetch 愉快的访问 Nodeloc 了,但是注意 url 格式:
   * 必须是相对路径
   * 使用 : 替代 .
   * 使用 . 替代 /
   *
   * 比如 https://nodeloc.cc/chat/api/me/channels 转换为 chat.api.me.channels
   * https://nodeloc.cc/session/passkey/challenge.json 转换为 session.passkey.challenge:json
   */

  // 这个时候就有人说了这b东西相当于在 fetch 外面套了路径翻译壳,你说得对 :) (实际上还是会自动处理csrf和cookie,以及自动登录)
}

main();

Message Bus

const MsgBus = require('./message-bus-client');

async function main() {
  const bus = new MsgBus('https://nodeloc.cc', {
    retryDelay: 0,
    pollTimeout: 60000
  });

  // 获取最新消息id
  let reqInfo = await client._fetch('chat.api.me.channels', { // 这里就要求了必须和 Nohope NodeLoc 搭配使用(强耦合了)。被资本 Discourse 做局了,要登录才可以访问这个api
    "method": "GET",
  });
  let infoData = await reqInfo.json();
  let chat_id = infoData.public_channels[0].last_message.chat_channel_id; // 获取第一个群的 ID
  let msg_id = infoData.public_channels[0].meta.message_bus_last_ids.channel_message_bus_last_id; // 获取第一个群的最后一条消息的 ID
  // 你问我为什么这么做?为什么不把这个获取id也封装了?去问 Discourse 的开发者怎么想的去 :(

  // 订阅吹水群
  bus.subscribe('/chat/' + chat_id, msg_id);

  bus.on('/chat/' + chat_id, async (data) => {
    let msg = data.chat_message;
    if (!msg || data.type !== 'processed') return; // 你问我为什么这么做?问 Discourse 的开发者怎么想的去
    console.log(msg); // 打印消息到控制台
  }, msg_id);

  // 开始轮询
  bus.start();
}

main();

关于CSRF令牌刷新问题,是缓存60s就换(主要是这个csrf刷新速度我也拿不定主意),100%不因为csrf无效而失败。

至于 MsgBus 为什么要手动获取 id,这相当于 MsgBus 库是 tcp,然而这里在用 http,非常垃圾对吧 。(实际上是因为这个id的获取方法的格式每个组件不太一样,没法封装【也可能我是傻逼找不到规律】,能用就行)

总结下来被资本 Discourse 做局了很狗屎,技术债多的一批,但是没办法啊,api就这样子,有没有大佬能重构(

都只要一个 node-fetch 依赖了,这么轻量的库还要什么飞机 (笑) 如果真有人用我这东西开发企业级应用那我考虑考虑重构。


粗糙但实用的轮子,如果你觉得不好用宁可自己面对神人Discourse逻辑写轮子,那您nb。
(Discourse的神奇思路真让人想不懂,论坛只支持新版浏览器浏览但死活不用websocket,还在用古老的长轮询,要是Discourse支持旧浏览器来避免使用websocket我不说,但是tm的它不支持旧浏览器啊,我chrome 108 都显示很快将无法参与社区讨论)


补:如果官方有写轮子但是我没发现那我就成小丑了

4 个赞

有没有无脑docker的

不会封装docker

e能不能用claude code封装

学习和支持一下吧