Mixin Network 是一个免费的 极速的端对端加密数字货币交易系统. 在本章中,你可以按教程在 Mixin Messenger 中创建一个 bot 来接收用户消息, 学到如何给机器人转比特币 或者 让机器人给你转比特币.
如果你运行的是 macOS, 手动到此下载 JDK12, 下载完成后,双击 jdk-11.0.2_osx-x64_bin.dmg, 在弹出的新窗口中,点击 JDK 11.0.2.pkg 文件,依提示一步一步完成安装,Java 会安装在 /Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk/Contents/Home/bin/ 目录中,将这个路径加入到$PATH
echo 'export PATH=/Library/Java/JavaVirtualMachines/jdk-11.0.2.jdk/Contents/Home/bin/:$PATH' >> ~/.bash_profile
source ~/.bash_profile
安装成功后,执行 java --version 将得到如下信息:
wenewzha:mixin_labs-java-bot wenewzhang$ java --version
java 11.0.2 2019-01-15 LTS
Java(TM) SE Runtime Environment 18.9 (build 11.0.2+9-LTS)
Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11.0.2+9-LTS, mixed mode)
Ubuntu
apt update
apt upgrade
apt install unzip
java --version
以 Ubuntu 16.04 为例,openjdk 版本的 Java 已经安装好了, 执行 java --version来验证安装情况。
root@ubuntu:~# java --version
openjdk 10.0.2 2018-07-17
OpenJDK Runtime Environment (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4)
OpenJDK 64-Bit Server VM (build 10.0.2+13-Ubuntu-1ubuntu0.18.04.4, mixed mode)
本教程采用 Gradle 来构建,你可从下面的地址来下载安装!Gradle 下载 macOS
brew update
brew install gradle
Ubuntu 下的 Gradle 太旧,我们手动安装它:
cd ~/Downloads
wget https://services.gradle.org/distributions/gradle-5.1.1-bin.zip
unzip gradle-5.1.1-bin.zip
解压 gradle-5.1.1-bin.zip 后,增加安装目录到$PATH 中:
echo 'export PATH=/root/gradle-5.1.1/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
当 Gradle 安装成功后, 执行gradle -v来验证安装情况:
root@ubuntu:~# gradle -v
------------------------------------------------------------
Gradle 5.1.1
------------------------------------------------------------
...
按下面的提示,到 mixin.one 创建一个 APPtutorial.
记下这些生成的参数 它们将用于 Config.java 中.
进入到你的工作目录,创建 mixin_labs-java-bot 目录, 执行gradle init来生成基本信息资料.
gradle init --dsl kotlin --type java-application --test-framework junit --project-name mixin_labs-java-bot
进入 src/main/java/mixin_labs/java/bot 目录,新建一个 Config.java, 填写如下内容:
Config.java
package mixin_labs.java.bot;
import mixin.java.sdk.MixinUtil;
import java.security.PrivateKey;
import java.security.interfaces.RSAPrivateKey;
import java.util.Base64;
import mixin.java.sdk.PrivateKeyReader;
public class Config {
public static final String CLIENT_ID = "b1ce2967-a534-417d-bf12-c86571e4eefa";
public static final String CLIENT_SECRET = "e6b14c6bbb20a43c603c468e225e6e4c666c940792cde43e41b34c3f1dd45713";
public static final String PIN = "536071";
public static final String SESSION_ID = "2f1c44a3-d4d2-4dd2-bdb6-8eda67694b91";
public static final String PIN_TOKEN = "ajJJngHmWgIfH3S2mgH4bAsoPeoXV6hI1KoTZW9AvFUK1R8e28X1zVRCcrOMVeXkvBKQeEMgRdX1kRgH3ksITTBm2mgK5eUnfBHUuRC85oKoQGB9e2Bp4O4ZKGg/6bqLeD66pnBPcO2s7VtgLSAK0tHa2jMzmGlWuxsO6Wo5JHE=";
private static RSAPrivateKey loadPrivateKey() {
try {
PrivateKey key =
new PrivateKeyReader(Config.class.getClassLoader().getResourceAsStream("rsa_private_key.txt"))
.getPrivateKey();
System.out.println(key);
return (RSAPrivateKey) key;
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
return null;
}
}
public static final RSAPrivateKey RSA_PRIVATE_KEY = loadPrivateKey();
public static final byte[] PAY_KEY = MixinUtil.decrypt(RSA_PRIVATE_KEY, PIN_TOKEN, SESSION_ID);
}
用你创建的 APP 的参数,替换文件中的内容: CLIENT_ID, client_id, CLIENT_SECRET, and the PIN, PIN_TOKEN, SESSION_ID.
创建 App.java 文件,内容如下:
App.java
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package mixin_labs.java.bot;
import mixin.java.sdk.MixinBot;
import mixin.java.sdk.MixinUtil;
import mixin.java.sdk.MIXIN_Category;
import mixin.java.sdk.MIXIN_Action;
import java.security.PrivateKey;
import java.security.interfaces.RSAPrivateKey;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
// import java.util.Base64;
import org.apache.commons.codec.binary.Base64;
import okhttp3.Response;
import okhttp3.WebSocket;
import okhttp3.WebSocketListener;
import okio.ByteString;
public class App {
public static void main(String[] args) {
MixinBot.connectToRemoteMixin(new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
System.out.println("[onOpen !!!]");
System.out.println("request header:" + response.request().headers());
System.out.println("response header:" + response.headers());
System.out.println("response:" + response);
// 请求获取所有 pending 的消息
MixinBot.sendListPendingMessages(webSocket);
}
@Override
public void onMessage(WebSocket webSocket, String text) {
System.out.println("[onMessage !!!]");
System.out.println("text: " + text);
}
@Override
public void onMessage(WebSocket webSocket, ByteString bytes) {
try {
System.out.println("[onMessage !!!]");
String msgIn = MixinUtil.bytesToJsonStr(bytes);
System.out.println("json: " + msgIn);
JsonObject obj = new JsonParser().parse(msgIn).getAsJsonObject();
MIXIN_Action action = MIXIN_Action.parseFrom(obj);
System.out.println(action);
MIXIN_Category category = MIXIN_Category.parseFrom(obj);
System.out.println(category);
if (action == MIXIN_Action.CREATE_MESSAGE && obj.get("data") != null &&
category != null ) {
String userId;
String messageId = obj.get("data").getAsJsonObject().get("message_id").getAsString();
MixinBot.sendMessageAck(webSocket, messageId);
switch (category) {
case PLAIN_TEXT:
String conversationId =
obj.get("data").getAsJsonObject().get("conversation_id").getAsString();
userId =
obj.get("data").getAsJsonObject().get("user_id").getAsString();
byte[] msgData = Base64.decodeBase64(obj.get("data").getAsJsonObject().get("data").getAsString());
MixinBot.sendText(webSocket,conversationId,userId,new String(msgData,"UTF-8"));
break;
default:
System.out.println("Category: " + category);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onClosing(WebSocket webSocket, int code, String reason) {
System.out.println("[onClosing !!!]");
System.out.println("code: " + code);
System.out.println("reason: " + reason);
}
@Override
public void onClosed(WebSocket webSocket, int code, String reason) {
System.out.println("[onClosed !!!]");
System.out.println("code: " + code);
System.out.println("reason: " + reason);
}
@Override
public void onFailure(WebSocket webSocket, Throwable t, Response response) {
System.out.println("[onFailure !!!]");
System.out.println("throwable: " + t);
System.out.println("response: " + response);
}
}, Config.RSA_PRIVATE_KEY, Config.CLIENT_ID, Config.SESSION_ID);
}
}
进入 src/main/resources, 新建文件:rsa_private_key.txt, 填写私钥信息:
rsa_private_key.txt
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
本教程依赖 mixin-java-sdk 现在回到项目目录,从 github 下载 mixin-java-sdk
mkdir libs
cd libs
wget https://github.com/wenewzhang/mixin-java-sdk/releases/download/v2/mixin-java-sdk.jar
增加依赖到 build.gradle.kts ,增加编译文件 compile(files("libs/mixin-java-sdk.jar")), 完整的依赖包如下:
dependencies {
// This dependency is found on compile classpath of this component and consumers.
implementation("com.google.guava:guava:26.0-jre")
// dependent on mixin-java-sdk, copy it to libs directory
compile(files("libs/mixin-java-sdk.jar"))
implementation("commons-codec:commons-codec:1.11")
implementation("com.auth0:java-jwt:3.5.0")
implementation("com.squareup.okio:okio:2.2.1")
implementation("com.squareup.okhttp3:okhttp:3.12.1")
implementation("com.google.code.gson:gson:2.8.5")
// Use JUnit test framework
testImplementation("junit:junit:4.12")
}
进入到 src/test/java/mixin_labs/java/bot, 注释掉下面的代码
AppTest.java
// assertNotNull("app should have a greeting", classUnderTest.getGreeting());
最后一步,回到项目目录 mixin_labs-java-bot, 编译并运行.
gradle build
gradle run
如果你看到如下信息,表示已经连接成功了,机器人小程序已经就绪,你可以发信息给他了!
response:Response{protocol=http/1.1, code=101, message=Switching Protocols, url=https://blaze.mixin.one/}
[onMessage !!!]
json: {"id":"4ee01b68-817e-4f29-bcb4-b40f7c163f61","action":"LIST_PENDING_MESSAGES"}
LIST_PENDING_MESSAGES
MixinBot.connectToRemoteMixin(new WebSocketListener() {
@Override
public void onOpen(WebSocket webSocket, Response response) {
MixinBot.sendListPendingMessages(webSocket);
}
连接到 Mixin Network 并发送"LISTPENDINGMESSAGES"消息,服务器以后会将收到的消息转发给此程序!
public void onMessage(WebSocket webSocket, ByteString bytes) {
try {
System.out.println("[onMessage !!!]");
String msgIn = MixinUtil.bytesToJsonStr(bytes);
当服务器给机器人推送消息的时候,机器人的 onMessage 函数会被调用
String messageId = obj.get("data").getAsJsonObject().get("message_id").getAsString();
MixinBot.sendMessageAck(webSocket, messageId);
机器人收到消息后需要发送响应给服务器,这样服务器就知道消息已经收到,不会再发一遍
switch (category) {
case PLAIN_TEXT:
String conversationId =
obj.get("data").getAsJsonObject().get("conversation_id").getAsString();
userId =
obj.get("data").getAsJsonObject().get("user_id").getAsString();
byte[] msgData = Base64.decodeBase64(obj.get("data").getAsJsonObject().get("data").getAsString());
MixinBot.sendText(webSocket,conversationId,userId,new String(msgData,"UTF-8"));
好了,你的第一个机器人小程序已经运行起来了, 你有什么新的想法,来试试吧!
完整的代码 这儿