
Mixin Network 是一个免费的 极速的端对端加密数字货币交易系统. 在本章中,你可以按教程在 Mixin Messenger 中创建一个 bot 来接收用户消息, 学到如何给机器人转帐 或者 让机器人给你转账.
通过本教程,你将学会如何用 nodejs 创建一个机器人 APP,让它能接受消息.
本教程是用 node.js 写的,在开始之前,我们先安装 node 与 yarn
macOS
brew install node yarn Ubuntu
curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add - echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list apt update apt upgrade apt install node yarn 打开终端,切换到你的工作目录,创建一个 nodejs-bot 的目录
mkdir nodejs-bot cd nodejs-bot/ 运行 yarn init 指令,按提示完成项目的创建, 完成后会生成 package.json 文件,代码例子如下:
yarn init { "name": "nodejs-bot", "version": "1.0.0", "main": "app.js",//默认生成的名字是 main.js "license": "MIT" } 本教程需要依赖一个 SDK, wangshijun/mixin-node-client. 所以我们先下载这个库. 在新生成的项目目录下,执行 yarn add mixin-node-client 来添加 mixin-node-client
yarn add mixin-node-client 现在,package.json 会增加下面几行:
"dependencies": { "mixin-node-client": "^0.6.0" } 如果你是克隆这个教程,在项目目录下执行 yarn 来下载安装依赖的软件包.
在写代码之前,我们先看图文教程,创建一个机器人 APP 教程.
记住下面三项,这是机器人发送接收消息所必须的: user id, session id, private key, Mixin Network 使用这三项进行数字签名。
https://github.com/wenewzhang/mixin_network-nodejs-bot2/blob/master/mixin_network-keys.png
创建一个 config.js 文件, 替换 clientID 为你的机器人的 id, sessionId 为你的机器人的 session id, privateKey 为你的私钥,aesKey,clientSecret, assetPin 我们后面才需要,这里可先不修改,但请保留这个数据不要删除!
config.js
// NOTE: please update this config file with your own module.exports = { clientId: '21042518-85c7-4903-bb19-f311813d1f51', clientSecret: 'will-generate-later', assetPin: 'will-generate-later', sessionId: '6ca194a4-727f-4e5f-a348-3c62987536ba', aesKey: 'will-generate-later', privateKey: `-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQC1P7QK7rK8lyX7X5t4A/reu7Q94xJkAllf1NPsW7zUdVgs/BCV f4RA6YK2prTpHHqXSCAzToEmou8R0xBMdnT/IQqijt0NzMpvrphiQrKrXEHrKrLm at6eZHYvLoGEPYjVq6RrgLkt2Mjld+RfHWd4zHXeqSCVfHAH67+gcPHYCwIDAQAB AoGADGotoeYRthtATcSRuJnFMEZ5JRgNpW4HwymnznPGLmNPQ92MIUFXxL555prq n2EFAKG/GuSQsh3M9FKZtjMS9l0aXpXy4T4ieBptkhahKbGVMLbQBru8wo/Pow3r r+DuNJs64ELvBYyydS7r1Fm/mtrd38Aq+4+04Z3UDW50AUkCQQDuhy8FoA3TKdZM mIEiPFb2dW8ohe8MsGM370S8HFPk7kdCaarJbiJCx1E+KjUxbkAeEFcLqKgaALTu IVCikIHNAkEAwoZvPaY0yFB1+V8HuToIR4X7AqWMy6WTBZ9U4wp34aNO21DLcrqf P40FHrHvqbWNK5bS8nSxLiv0kYL6+ezJNwJAO/GxOYKttsGu33T8DvSHDk0Y8GAo YVH6vVXeOkAMPV48fk47439QEOQyYKMO1ytT5bpJhd6O0GoZDjdFInWaiQJAAq4l hDzxBz2MkpYLnjK9gHbJIZ00Vm3+m5o5ajNvuW0tnfn8A6WsogyIYIblHXqB6nLW jz6qXk9+vC6I1L69ewJAasE+oC3TMblSOC9xqeBQgm8BPhb0UwJL4UuZLOSyUETr +bAwyiZ37Cc7r/nxKhVH+FwMCVoeNUMcRIYYMRjwmg== -----END RSA PRIVATE KEY-----`, }; 在项目目录下创建一个 app.js, 并将下面的代码粘贴进去.
const { SocketClient, isMessageType } = require('mixin-node-client'); const { HttpClient } = require('mixin-node-client'); const cOnfig= require('./config'); const client = new SocketClient(config); const ValidActiOns= ["ACKNOWLEDGE_MESSAGE_RECEIPT" ,"CREATE_MESSAGE", "LIST_PENDING_MESSAGES"]; console.log('Supported MessageSenders by SocketClient', client.getMessageSenders()); console.log(client.getMessageSenders()); // Listen and react to socket messages client.on( 'message', client.getMessageHandler(message => { console.log('Message Received', message); if (ValidActions.indexOf(message.action) > -1) { if (message.action === 'ACKNOWLEDGE_MESSAGE_RECEIPT') {console.log("ignore receipt");return;} if (isMessageType(message, 'text')) { const text = message.data.data.toLowerCase(); if ( (message.data.category === "PLAIN_TEXT") && (message.action === "CREATE_MESSAGE") ) { var parameter4IncomingMsg = {"message_id":message.data.message_id, "status":"READ"}; var RspMsg = {"id":client.getUUID(), "action":"ACKNOWLEDGE_MESSAGE_RECEIPT", "params":parameter4IncomingMsg}; client.sendRaw(RspMsg); if (text === 'pay') { // todo: pay } return client.sendText(text, message); } } return Promise.resolve(message); } else console.log("unknow action") })); client.on('error', err => console.error(err.message)); 开始执行
node app.js 如果你的配置文件有错,可能会出现下面的提示:
nodejsdemo node app.js Supported MessageSenders by SocketClient [ 'sendText', 'sendImage', 'sendVideo', 'sendData', 'sendSticker', 'sendContact', 'sendButton', 'sendButtons', 'sendApp' ] [ 'sendText', 'sendImage', 'sendVideo', 'sendData', 'sendSticker', 'sendContact', 'sendButton', 'sendButtons', 'sendApp' ] Message Received { id: '00000000-0000-0000-0000-000000000000', action: 'ERROR', error: { status: 202, code: 401, description: 'Unauthorized, maybe invalid token.' } } 如果一切顺利,机器人将连接上服务器并等待服务器的消息,提示如下:
nodejsdemo node app.js Supported MessageSenders by SocketClient [ 'sendText', 'sendImage', 'sendVideo', 'sendData', 'sendSticker', 'sendContact', 'sendButton', 'sendButtons', 'sendApp' ] [ 'sendText', 'sendImage', 'sendVideo', 'sendData', 'sendSticker', 'sendContact', 'sendButton', 'sendButtons', 'sendApp' ] Message Received { id: '30e3c929-f6b7-46c2-9e46-6634af66daab', action: 'LIST_PENDING_MESSAGES' } 打开Mixin Messenger,将你的机器人加为好友,(比如,这个机器人的 ID 是 7000101639) 然后就可以给它发消息了! 比如你发一个"hi"
https://github.com/wenewzhang/mixin_network-nodejs-bot2/blob/master/mixin_messenger-sayhi.png
终端将显示如下:
Message Received { id: 'de4671c2-8873-419b-92b0-0d6ae8381940', action: 'LIST_PENDING_MESSAGES' } Message Received { id: 'a41816ca-2b65-4668-abdd-4526c1d29015', action: 'CREATE_MESSAGE', data: { type: 'message', representative_id: '', quote_message_id: '', conversation_id: 'c5458ec8-5e95-3e64-ae63-d4dfc3135c9e', user_id: '28ee416a-0eaa-4133-bc79-9676909b7b4e', message_id: 'a93ebfca-3d3f-44a9-9d63-3ad41ddca4b8', category: 'PLAIN_TEXT', data: 'hi', status: 'SENT', source: 'CREATE_MESSAGE', created_at: '2019-01-10T03:44:12.600158Z', updated_at: '2019-01-10T03:44:12.600158Z' } } Message Received { id: '810b93d9-56d4-413a-9837-6dc241e36ed0', action: 'ACKNOWLEDGE_MESSAGE_RECEIPT' } ignore receipt Message Received { id: 'd45c5139-8201-4f8a-aa2f-86c98ba3a849', action: 'CREATE_MESSAGE', data: { type: 'message', representative_id: '', quote_message_id: '', conversation_id: '', user_id: 'daf8b473-39a0-4419-991a-77f30d28dd6d', message_id: '9054acea-1a62-4716-9fa3-1a8c70a2165a', category: '', data: '', status: 'SENT', source: 'CREATE_MESSAGE', created_at: '2019-01-10T03:44:22.540536153Z', upated_at: '2019-01-10T03:44:22.540536153Z' } } Message Received { id: 'cf69c7a2-787b-4a91-be22-f51f38338179', action: 'ACKNOWLEDGE_MESSAGE_RECEIPT', data: { type: 'message', representative_id: '', quote_message_id: '', conversation_id: '', user_id: '', message_id: '9054acea-1a62-4716-9fa3-1a8c70a2165a', category: '', data: '', status: 'DELIVERED', source: 'ACKNOWLEDGE_MESSAGE_RECEIPT', created_at: '0001-01-01T00:00:00Z', updated_at: '2019-01-10T03:44:23.236843Z' } } ignore receipt Message Received { id: 'daa66945-abb6-4b8f-bc6a-04c4ccb6a837', action: 'ACKNOWLEDGE_MESSAGE_RECEIPT', data: { type: 'message', representative_id: '', quote_message_id: '', conversation_id: '', user_id: '', message_id: '9054acea-1a62-4716-9fa3-1a8c70a2165a', category: '', data: '', status: 'READ', source: 'ACKNOWLEDGE_MESSAGE_RECEIPT', created_at: '0001-01-01T00:00:00Z', updated_at: '2019-01-10T03:44:23.787562Z' } } ignore receipt 机器人接受消息前,先建立到服务器的连接,再利用签名信息进行登陆认证。
app.js
const { SocketClient, isMessageType } = require('mixin-node-client'); const cOnfig= require('./config'); const client = new SocketClient(config); 开启一个侦听,在这对收到的消息进行处理
client.on( 'message', client.getMessageHandler(message => { console.log('Message Received', message); return Promise.resolve(message); }) ); 接收消息, 进行pay相关的逻辑处理
if (ValidActions.indexOf(message.action) > -1) { if (message.action === 'ACKNOWLEDGE_MESSAGE_RECEIPT') {console.log("ignore receipt");return;} if (isMessageType(message, 'text')) { const text = message.data.data.toLowerCase(); if ( (message.data.category === "PLAIN_TEXT") && (message.action === "CREATE_MESSAGE") ) { //todo: tell the server you got this message if (text === 'pay') { //todo: pay } return client.sendText(text, message); } } return Promise.resolve(message); } else console.log("unknow action") 除了发送文本消息之外,还可以发送图片等消息,详细的消息类型请参考这里.
对于每一条接收到的消息,将消息号( message_id)做为参数,回应服务器,action 为 ACKNOWLEDGE_MESSAGE_RECEIPT! 如果不回应,机器人下次登入,会重新获得消息。
if ( (message.data.category === "PLAIN_TEXT") && (message.action === "CREATE_MESSAGE") ) { // READ message start var parameter4IncomingMsg = {"message_id":message.data.message_id, "status":"READ"}; var RspMsg = {"id":client.getUUID(), "action":"ACKNOWLEDGE_MESSAGE_RECEIPT", "params":parameter4IncomingMsg}; client.sendRaw(RspMsg); // READ message end return client.sendText(text, message); node app.js