Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.wechat.ferry.controller;

import com.alibaba.fastjson2.JSONObject;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -14,6 +15,7 @@
import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseSqlReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseTableReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDeleteGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDownloadAttachReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfInviteGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfPassFriendApplyReq;
Expand Down Expand Up @@ -41,10 +43,12 @@
import com.wechat.ferry.entity.vo.response.WxPpWcfSendXmlMsgResp;
import com.wechat.ferry.enums.ResponseCodeEnum;
import com.wechat.ferry.service.WeChatDllService;
import com.wechat.ferry.utils.PathUtils;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

/**
* 控制层-微信DLL处理
Expand Down Expand Up @@ -258,16 +262,68 @@ public TResponse<Object> receiveTransfer(@Validated @RequestBody WxPpWcfReceiveT
return TResponse.ok(ResponseCodeEnum.SUCCESS);
}

// @ApiOperation(value = "下载图片、视频、文件", notes = "queryMsgTypeList")
// @PostMapping(value = "/list/msgType")
// public TResponse<Object> queryMsgTypeList() {
// return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
// }
//
// @ApiOperation(value = "解密图片", notes = "queryMsgTypeList")
// @PostMapping(value = "/list/msgType")
// public TResponse<Object> queryMsgTypeList() {
// return TResponse.ok(ResponseCodeEnum.SUCCESS, list);
// }
/**
* 下载视频 add by wmz 2025-05-01
*
* @param request
* @return
* @throws Exception
*/
@ApiOperation(value = "下载视频", notes = "download_video")
@PostMapping(value = "/download/video")
public TResponse<Object> downloadVideo(@Validated @RequestBody WxPpWcfDownloadAttachReq request) throws Exception {
String path = weChatDllService.downloadVideo(request);
if (path != null) {
JSONObject pathJson = new JSONObject();
pathJson.put("path", path);
return TResponse.ok(ResponseCodeEnum.SUCCESS, pathJson);
}
return TResponse.ok(ResponseCodeEnum.FAILED);
}

/**
* 下载图片 add by wmz 2025-05-02
*
* @param request
* @return
* @throws Exception
*/
@ApiOperation(value = "下载图片", notes = "download_picture")
@PostMapping(value = "/download/picture")
public TResponse<Object> downloadPicture(@Validated @RequestBody WxPpWcfDownloadAttachReq request) throws Exception {
//check parameter
String dir = request.getDir();
if (!StringUtils.hasText(dir)) {
log.info("需要指定图片的路径dir");
return TResponse.fail("需要指定图片的路径dir");
}
boolean res = PathUtils.createDir(dir);
if (!res) {
return TResponse.fail("图片路径创建失败" + dir);
}

String path = weChatDllService.downloadPicture(request);
if (path != null) {
JSONObject pathJson = new JSONObject();
pathJson.put("path", path);
return TResponse.ok(ResponseCodeEnum.SUCCESS, pathJson);
}
return TResponse.ok(ResponseCodeEnum.FAILED);
}

/**
* 暂未实现 add by mz 2025-05-01
*
* @param request
* @return
* @throws Exception
*/
@ApiOperation(value = "登陆二维码", notes = "loginQR")
@PostMapping(value = "/loginQR")
public TResponse<Object> loginQR(@Validated @RequestBody WxPpWcfDownloadAttachReq request) throws Exception {
String path = weChatDllService.loginQR();
return TResponse.ok(ResponseCodeEnum.SUCCESS, path);
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.wechat.ferry.entity.vo.request;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotBlank;

/**
* 请求入参-下载附件信息
*
* @author wmz
* @date 2025-05-02
*/
@Data
@ApiModel(value = "wxPpWcfDownloadAttachReq", description = "个微WCF下载附件请求入参")
public class WxPpWcfDownloadAttachReq {

/**
* 消息接收人
* 消息接收人,私聊为 wxid(wxid_xxxxxxxxxxxxxx)
* 群聊为 roomid(xxxxxxxxxx@chatroom)
*/
@NotBlank(message = "消息id不能为空")
@ApiModelProperty(value = "消息id")
private Long id;

/**
* 文件的extra
*/
@ApiModelProperty(value = "extra")
private String extra;

/**
* 缩略图thumb
*/
// @NotBlank(message = "thumb不能为空")
@ApiModelProperty(value = "缩略图thumb")
private String thumb;

/**
* dir (str): 存放图片的目录。下载图片需要。暂不支持视频
*/
@ApiModelProperty(value = "图片存放路径dir")
private String dir;

}
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,12 @@ public void connectRPC(String url, SDK INSTANCE) {

public Response sendCmd(Request req) {
try {
// 设置发送 20 秒超时
cmdSocket.setSendTimeout(20000);
// 不知道之前设置20S有啥特殊情况???这里设置超时时间 5s --> 参考Python版本
// 防止无响应的时候线程一直阻塞--ReceiveTimeout
// modify by wmz 2025-05-03
cmdSocket.setSendTimeout(5000);
cmdSocket.setReceiveTimeout(5000);

ByteBuffer bb = ByteBuffer.wrap(req.toByteArray());
cmdSocket.send(bb);
ByteBuffer ret = ByteBuffer.allocate(BUFFER_SIZE);
Expand Down Expand Up @@ -655,7 +659,9 @@ public int revokeMsg(Integer id) {
* @param src 加密的图片路径
* @param dir 保存图片的目录
* @return 解密图片的保存路径
* @see WeChatDllServiceImpl decryptImage
*/
@Deprecated
public String decryptImage(String src, String dir) {
Wcf.DecPath build = Wcf.DecPath.newBuilder().setSrc(src).setDst(dir).build();
Request req = Request.newBuilder().setFuncValue(Functions.FUNC_DECRYPT_IMAGE_VALUE).setDec(build).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseSqlReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseTableReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDeleteGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDownloadAttachReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfInviteGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfPassFriendApplyReq;
Expand Down Expand Up @@ -487,4 +488,39 @@ WxPpWcfSendRichTextMsgResp sendRichTextMsg(String recipient, String name, String
*/
String receiveTransfer(String weChatUid, String transferId, String transactionId);

/**
* 下载视频文件
*
* @param request 请求入参
* @return 文件路径
*
* @author wmz
* @throws java.lang.Exception
* @date 2025-05-02
*/
String downloadVideo(WxPpWcfDownloadAttachReq request) throws Exception;

/**
* 下载图片
*
* @param request 请求入参
* @return 文件路径
*
* @author wmz
* @throws java.lang.Exception
* @date 2025-05-02
*/
String downloadPicture(WxPpWcfDownloadAttachReq request) throws Exception;

/**
* 获取登录二维码
*
* @return 文件路径
*
* @author wmz
* @throws java.lang.Exception
* @date 2025-05-02
*/
String loginQR() throws Exception;

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseSqlReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDatabaseTableReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDeleteGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfDownloadAttachReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfInviteGroupMemberReq;
import com.wechat.ferry.entity.vo.request.WxPpWcfPassFriendApplyReq;
Expand Down Expand Up @@ -56,6 +57,8 @@
import com.wechat.ferry.handle.WeChatSocketClient;
import com.wechat.ferry.service.WeChatDllService;
import com.wechat.ferry.utils.HttpClientUtil;
import com.wechat.ferry.utils.PathUtils;
import java.io.File;

import lombok.extern.slf4j.Slf4j;

Expand Down Expand Up @@ -762,5 +765,131 @@ private void checkClientStatus() {
throw new BizException("微信客户端未登录或状态异常,请人工关闭本服务之后,退出微信客户端在重启本服务!");
}
}


@Override
public String loginQR() throws Exception {

long startTime = System.currentTimeMillis();
// 公共校验
checkClientStatus();
log.info("[登录]-[获取二维码]-入参打印:{}", "");
// # 强制等待 1 秒让数据入库,避免那帮人总是嗷嗷叫超时
Thread.sleep(1000);
//第一步
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_REFRESH_QRCODE_VALUE)
.build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
rsp.getStatus();
// RequestResponseBodyMethodProcessor s;
long endTime = System.currentTimeMillis();
log.info("[登录]-[获取二维码]-处理结束,耗时:{}ms", (endTime - startTime));
System.out.println(rsp.getStr());
return rsp.getStr();
}

@Override
public String downloadVideo(WxPpWcfDownloadAttachReq request) throws Exception {
long startTime = System.currentTimeMillis();
// 公共校验
checkClientStatus();
log.info("[下载]-[下载视频]-入参打印:{}", request);
int status = attachDownload(request.getId(), "", request.getThumb());
if (status != 0) {
log.info("{}:下载视频出错", request.getId());
return null;
}
//第二步,检测文件,指定下载的目录
String base = PathUtils.removeExtension(request.getThumb());
String filePath = base + ".mp4";
String path = null;
for (int i = 0; i < 30; i++) {
if (new File(filePath).exists()) {
path = filePath;
log.info("视频下载完毕:{}", path);
break;
} else {
log.info("等待下载中:{}", i);
Thread.sleep(1000);
}
}
long endTime = System.currentTimeMillis();
log.info("[下载]-[下载视频]-处理结束,耗时:{}ms", (endTime - startTime));
return path;
}

@Override
public String downloadPicture(WxPpWcfDownloadAttachReq request) throws Exception {
long startTime = System.currentTimeMillis();
// 公共校验
checkClientStatus();
log.info("[下载]-[下载图片]-入参打印:{}", request);
int status = attachDownload(request.getId(), request.getExtra(), "");
if (status != 0) {
log.info("{}:下载出错", request.getId());
return null;
}
//第二步解密图片--下载图片
String filePath = decryptImage(request.getExtra(), request.getDir());
String path = null;
for (int i = 0; i < 15; i++) {
if (new File(filePath).exists()) {
log.info("图片下载完毕:{}", filePath);
path = filePath;
break;
} else {
log.info("等待下载中:{}", i);
Thread.sleep(1000);
}
}
long endTime = System.currentTimeMillis();
log.info("[下载]-[下载图片]-处理结束,耗时:{}ms", (endTime - startTime));
return path;
}

/**
* 下载附件(图片、视频、文件)。这方法别直接调用。
*
* @param id
* @param extra
* @param thumb
* @return int: 0 为成功, 其他失败。
* @throws Exception
*/
private int attachDownload(long id, String extra, String thumb) {
try {
//# 强制等待 1 秒让数据入库,避免那帮人总是嗷嗷叫超时
Thread.sleep(1000);
//第一步,下载
Wcf.AttachMsg msg = Wcf.AttachMsg.newBuilder().setId(id)
.setExtra(extra).setThumb(thumb)
.build();
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_DOWNLOAD_ATTACH_VALUE)
.setAtt(msg)
.build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
return rsp.getStatus();
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}

/**
* 解密图片
*
* @param srcPath 加密的图片路径
* @param dir 保存图片的目录
* @return 是否成功
*/
public String decryptImage(String srcPath, String dir) {
Wcf.DecPath build = Wcf.DecPath.newBuilder().setSrc(srcPath).setDst(dir).build();
Wcf.Request req = Wcf.Request.newBuilder().setFuncValue(Wcf.Functions.FUNC_DECRYPT_IMAGE_VALUE).setDec(build).build();
Wcf.Response rsp = wechatSocketClient.sendCmd(req);
if (rsp != null && rsp.getStatus() == 0) {
return rsp.getStr();
}
return null;
}

}
Loading