v30.2.4适配java客户端

This commit is contained in:
猜火车 2024-07-10 15:21:19 +08:00
parent 1c1625ad7e
commit 0744cf225d
5 changed files with 7663 additions and 3359 deletions

View File

@ -4,7 +4,7 @@
## 快速开始
* 下载 [最新发布的文件](https://github.com/lich0821/WeChatFerry/releases/latest),解压到 `WeChatFerry\clients\java\wcferry\src\main\resources\win32-x86-64`
* 下载 [最新发布的文件](https://github.com/lich0821/WeChatFerry/releases/latest),解压到 `WeChatFerry\clients\java\wcferry\dll`目录下
* 使用惯用 IDE打开工程编译运行。
@ -68,9 +68,9 @@ cd C:/Projs/WeChatFerry/java/wcferry/src/main/java
protoc.exe --java_out=. --proto_path=C:\Projs\WeChatFerry\WeChatFerry\rpc\proto wcf.proto
```
### 添加 `wcferry` 依赖
### 添加 `dll` 依赖
`wcf.exe` 、 `spy.dll` 、 `spy_debug.dll` 添加到 `WeChatFerry\clients\java\wcferry\src\main\resources\win32-x86-64`。
将 `spy.dll` 、 `spy_debug.dll`、 `spy.dll` 添加到 `WeChatFerry\clients\java\wcferry\dll`。
### 其他问题

View File

@ -5,8 +5,6 @@ import io.sisu.nng.Socket;
import io.sisu.nng.pair.Pair1Socket;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;
@ -16,60 +14,41 @@ import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class Client {
private static final Logger logger = LoggerFactory.getLogger(Client.class);
private final int BUFFER_SIZE = 16 * 1024 * 1024; // 16M
private static final int BUFFER_SIZE = 16 * 1024 * 1024; // 16M
private Socket cmdSocket = null;
private Socket msgSocket = null;
private String host = "127.0.0.1";
private int port = 10086;
private static String DEFAULT_HOST = "127.0.0.1";
private static int PORT = 10086;
private static String CMDURL = "tcp://%s:%s";
private boolean isReceivingMsg = false;
private boolean isLocalHostPort = false;
private BlockingQueue<WxMsg> msgQ;
private String wcfPath;
public Client(String host, int port) {
private String host;
private int port;
public Client() {
this(DEFAULT_HOST, PORT, false);
}
public Client(String host, int port, boolean debug) {
this.host = host;
this.port = port;
String cmdUrl = "tcp://" + host + ":" + port;
connectRPC(cmdUrl);
}
public Client(int port, boolean debug) {
initClient(this.host, port, debug);
}
public Client(boolean debug) {
initClient(this.host, this.port, debug);
}
private void initClient(String host, int port, boolean debug) {
try {
URL url = this.getClass().getResource("/win32-x86-64/wcf.exe");
wcfPath = url.getFile();
String[] cmd = new String[4];
cmd[0] = wcfPath;
cmd[1] = "start";
cmd[2] = Integer.toString(port);
if (debug) {
cmd[3] = "debug";
} else {
cmd[3] = "";
}
int status = Runtime.getRuntime().exec(cmd).waitFor();
int status = SDK.INSTANCE.WxInitSDK(debug, 10086);
if (status != 0) {
logger.error("启动 RPC 失败: {}", status);
System.exit(-1);
}
connectRPC(String.format(CMDURL, host, port));
if (DEFAULT_HOST.equals(host) || "localhost".equalsIgnoreCase(host)) {
isLocalHostPort = true;
String cmdUrl = "tcp://" + host + ":" + port;
connectRPC(cmdUrl);
} catch (Exception e) {
logger.error("初始化失败: {}", e);
System.exit(-1);
}
}
private void connectRPC(String url) {
public void connectRPC(String url) {
try {
cmdSocket = new Pair1Socket();
cmdSocket.dial(url);
@ -81,26 +60,13 @@ public class Client {
logger.error("连接 RPC 失败: ", e);
System.exit(-1);
}
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
logger.info("关闭...");
diableRecvMsg();
if (isLocalHostPort) {
try {
String[] cmd = new String[2];
cmd[0] = wcfPath;
cmd[1] = "stop";
Process process = Runtime.getRuntime().exec(cmd);
int status = process.waitFor();
if (status != 0) {
System.err.println("停止机器人失败: " + status);
SDK.INSTANCE.WxDestroySDK();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
}));
}
private Response sendCmd(Request req) {
@ -189,7 +155,8 @@ public class Client {
*/
public List<DbRow> querySql(String db, String sql) {
DbQuery dbQuery = DbQuery.newBuilder().setSql(sql).setDb(db).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_EXEC_DB_QUERY_VALUE).setQuery(dbQuery).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_EXEC_DB_QUERY_VALUE)
.setQuery(dbQuery).build();
Response rsp = sendCmd(req);
if (rsp != null) {
return rsp.getRows().getRowsList();
@ -219,7 +186,8 @@ public class Client {
* @return
*/
public Map<String, String> getDbTables(String db) {
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_DB_TABLES_VALUE).setStr(db).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_GET_DB_TABLES_VALUE).setStr(db)
.build();
Response rsp = sendCmd(req);
Map<String, String> tables = new HashMap<>();
if (rsp != null) {
@ -244,8 +212,10 @@ public class Client {
* "wxid_xxxxxxxxxxxxx1,wxid_xxxxxxxxxxxxx2");
**/
public int sendText(String msg, String receiver, String aters) {
Wcf.TextMsg textMsg = Wcf.TextMsg.newBuilder().setMsg(msg).setReceiver(receiver).setAters(aters).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_TXT_VALUE).setTxt(textMsg).build();
Wcf.TextMsg textMsg = Wcf.TextMsg.newBuilder().setMsg(msg).setReceiver(receiver).setAters(aters)
.build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_TXT_VALUE).setTxt(textMsg)
.build();
logger.debug("sendText: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
@ -265,7 +235,8 @@ public class Client {
*/
public int sendImage(String path, String receiver) {
Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(path).setReceiver(receiver).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_IMG_VALUE).setFile(pathMsg).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_IMG_VALUE).setFile(pathMsg)
.build();
logger.debug("sendImage: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
@ -285,7 +256,8 @@ public class Client {
*/
public int sendFile(String path, String receiver) {
Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(path).setReceiver(receiver).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_FILE_VALUE).setFile(pathMsg).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_FILE_VALUE).setFile(pathMsg)
.build();
logger.debug("sendFile: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
@ -306,8 +278,10 @@ public class Client {
* @return 发送结果状态码
*/
public int sendXml(String receiver, String xml, String path, int type) {
Wcf.XmlMsg xmlMsg = Wcf.XmlMsg.newBuilder().setContent(xml).setReceiver(receiver).setPath(path).setType(type).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_XML_VALUE).setXml(xmlMsg).build();
Wcf.XmlMsg xmlMsg = Wcf.XmlMsg.newBuilder().setContent(xml).setReceiver(receiver).setPath(path)
.setType(type).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_XML_VALUE).setXml(xmlMsg)
.build();
logger.debug("sendXml: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
@ -327,7 +301,8 @@ public class Client {
*/
public int sendEmotion(String path, String receiver) {
Wcf.PathMsg pathMsg = Wcf.PathMsg.newBuilder().setPath(path).setReceiver(receiver).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_EMOTION_VALUE).setFile(pathMsg).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_SEND_EMOTION_VALUE)
.setFile(pathMsg).build();
logger.debug("sendEmotion: {}", bytesToHex(req.toByteArray()));
Response rsp = sendCmd(req);
int ret = -1;
@ -348,7 +323,8 @@ public class Client {
public int acceptNewFriend(String v3, String v4) {
int ret = -1;
Verification verification = Verification.newBuilder().setV3(v3).setV4(v4).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_ACCEPT_FRIEND_VALUE).setV(verification).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_ACCEPT_FRIEND_VALUE)
.setV(verification).build();
Response rsp = sendCmd(req);
if (rsp != null) {
ret = rsp.getStatus();
@ -366,7 +342,8 @@ public class Client {
public int addChatroomMembers(String roomID, String wxIds) {
int ret = -1;
MemberMgmt memberMgmt = MemberMgmt.newBuilder().setRoomid(roomID).setWxids(wxIds).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_ADD_ROOM_MEMBERS_VALUE).setM(memberMgmt).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_ADD_ROOM_MEMBERS_VALUE)
.setM(memberMgmt).build();
Response rsp = sendCmd(req);
if (rsp != null) {
ret = rsp.getStatus();
@ -384,7 +361,8 @@ public class Client {
public boolean decryptImage(String srcPath, String dstPath) {
int ret = -1;
DecPath build = DecPath.newBuilder().setSrc(srcPath).setDst(dstPath).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_DECRYPT_IMAGE_VALUE).setDec(build).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_DECRYPT_IMAGE_VALUE)
.setDec(build).build();
Response rsp = sendCmd(req);
if (rsp != null) {
ret = rsp.getStatus();
@ -441,7 +419,7 @@ public class Client {
msgSocket.dial(url);
msgSocket.setReceiveTimeout(2000); // 2 秒超时
} catch (Exception e) {
logger.error("创建消息 RPC 失败: {}", e);
logger.error("创建消息 RPC 失败", e);
return;
}
ByteBuffer bb = ByteBuffer.allocate(BUFFER_SIZE);
@ -457,7 +435,7 @@ public class Client {
try {
msgSocket.close();
} catch (Exception e) {
logger.error("关闭连接失败: {}", e);
logger.error("关闭连接失败", e);
}
}
@ -475,13 +453,9 @@ public class Client {
}
isReceivingMsg = true;
msgQ = new ArrayBlockingQueue<WxMsg>(qSize);
msgQ = new ArrayBlockingQueue<>(qSize);
String msgUrl = "tcp://" + this.host + ":" + (this.port + 1);
Thread thread = new Thread(new Runnable() {
public void run() {
listenMsg(msgUrl);
}
});
Thread thread = new Thread(() -> listenMsg(msgUrl));
thread.start();
}
@ -522,15 +496,17 @@ public class Client {
gender = "未知";
}
logger.info("{}, {}, {}, {}, {}, {}, {}", c.getWxid(), c.getName(), c.getCode(), c.getCountry(), c.getProvince(), c.getCity(), gender);
logger.info("{}, {}, {}, {}, {}, {}, {}", c.getWxid(), c.getName(), c.getCode(),
c.getCountry(), c.getProvince(), c.getCity(), gender);
}
}
public void printWxMsg(WxMsg msg) {
logger.info("{}[{}]:{}:{}:{}\n{}", msg.getSender(), msg.getRoomid(), msg.getId(), msg.getType(), msg.getXml().replace("\n", "").replace("\t", ""), msg.getContent());
logger.info("{}[{}]:{}:{}:{}\n{}", msg.getSender(), msg.getRoomid(), msg.getId(), msg.getType(),
msg.getXml().replace("\n", "").replace("\t", ""), msg.getContent());
}
public String bytesToHex(byte[] bytes) {
private String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02x", b));
@ -544,3 +520,4 @@ public class Client {
}
}
}

View File

@ -11,7 +11,7 @@ public class Main {
// Client client = new Client("127.0.0.1", 10086);
// 本地启动 RPC
Client client = new Client(true); // 默认 10086 端口
Client client = new Client(); // 默认 10086 端口
// Client client = new Client(10088,true); // 也可以指定端口
// 是否已登录
@ -60,3 +60,4 @@ public class Main {
client.keepRunning();
}
}

View File

@ -0,0 +1,30 @@
package com.iamteer;
import com.sun.jna.Library;
import com.sun.jna.Native;
/**
* SDK.dll的接口类
* @Description
* @Author xinggq
* @Date 2024/7/10
*/
public interface SDK extends Library {
// 读取项目根目录下dll文件夹而且只能写绝对路径放在resource下会有问题暂时先不解决
// 打包后dll文件应该放在jar外这样dll更新不需要生成jar包重启下就ok了
SDK INSTANCE = Native.load(System.getProperty("user.dir")+"\\dll\\sdk.dll", SDK.class);
/**
* 初始化SDK
* @param debug
* @param port
* @return
*/
int WxInitSDK(boolean debug, int port);
/**
* 退出SDK
* @return
*/
int WxDestroySDK();
}

File diff suppressed because it is too large Load Diff