feat: 增强二维码和图片代理功能
主要修改: 1. 在QrProxyController中新增多个图片代理接口,包括首页、首次赏金、中途赏金和结束赏金图片的获取。 2. 更新LinkController中的链接状态查询逻辑,简化日志输出。 3. 在LinkStatusService中优化链接状态处理逻辑,增加对USING状态的过期检查。 4. 在ScriptClient中新增通用图片获取方法,支持从脚本端获取图片数据。 5. 更新SecurityConfig,允许公开访问二维码和游戏界面数据接口。 技术细节: - 新增GameInterfaceResponse DTO以支持游戏界面数据的返回格式。 - 通过脚本端接口实现图片的动态获取和链接状态的自动刷新。
This commit is contained in:
@@ -54,6 +54,23 @@ public class ScriptClient {
|
||||
.doOnError(e -> log.warn("ScriptClient.getQrPng error path={} err={}", path, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用图片获取方法
|
||||
* @param path 图片路径,如 /{codeNo}/首次主页.png
|
||||
* @return 图片数据
|
||||
*/
|
||||
public Mono<byte[]> getImagePng(String path) {
|
||||
log.debug("获取图片: path={}", path);
|
||||
return webClient.get()
|
||||
.uri(path)
|
||||
.accept(MediaType.IMAGE_PNG)
|
||||
.retrieve()
|
||||
.bodyToMono(byte[].class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(data -> log.debug("获取图片成功: path={}, 数据大小={}字节", path, data != null ? data.length : 0))
|
||||
.doOnError(e -> log.warn("获取图片失败: path={}, error={}", path, e.toString()));
|
||||
}
|
||||
|
||||
public Mono<String> getText(String path) {
|
||||
return webClient.get()
|
||||
.uri(path)
|
||||
@@ -138,6 +155,22 @@ public class ScriptClient {
|
||||
.doOnError(e -> log.warn("刷新操作失败: codeNo={}, error={}", codeNo, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断刷新接口 - 统一管理刷新判断逻辑
|
||||
*/
|
||||
public Mono<String> checkRefresh() {
|
||||
String url = "http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断刷新&f4=刷新";
|
||||
log.info("调用判断刷新接口: {}", url);
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> log.info("判断刷新接口调用成功: result={}", result))
|
||||
.doOnError(e -> log.warn("判断刷新接口调用失败: {}", e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查设备是否已上号 - 根据您提供的API示例
|
||||
* URL格式: http://36.138.184.60:1234/yijianwan_netfile/readMsg?文件名=判断上号&对象名=f1
|
||||
@@ -229,6 +262,24 @@ public class ScriptClient {
|
||||
.doOnSuccess(result -> log.debug("设置次数成功: codeNo={}, times={}, result={}", codeNo, times, result))
|
||||
.doOnError(e -> log.warn("设置次数失败: codeNo={}, times={}, error={}", codeNo, times, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存总次数(使用f4参数格式)
|
||||
* @param times 总次数
|
||||
* @return 保存结果
|
||||
*/
|
||||
public Mono<String> saveTotalTimes(int times) {
|
||||
String url = String.format("http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=总次数&f4=%d", times);
|
||||
log.info("开始调用保存总次数接口: times={}, url={}", times, url);
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> log.info("保存总次数接口调用成功: url={}, result={}", url, result))
|
||||
.doOnError(e -> log.warn("保存总次数接口调用失败: times={}, error={}", times, e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.scheduler.Schedulers;
|
||||
|
||||
@@ -37,6 +38,7 @@ public class LinkStatusService {
|
||||
private final ScriptClient scriptClient;
|
||||
private final DeviceCodeMappingService deviceCodeMappingService;
|
||||
|
||||
|
||||
// 状态描述映射
|
||||
private static final Map<String, String> STATUS_DESC_MAP = new HashMap<>();
|
||||
static {
|
||||
@@ -47,12 +49,13 @@ public class LinkStatusService {
|
||||
STATUS_DESC_MAP.put("EXPIRED", "已过期");
|
||||
}
|
||||
|
||||
public LinkStatusService(LinkTaskMapper linkTaskMapper, LinkBatchMapper linkBatchMapper,
|
||||
ScriptClient scriptClient, DeviceCodeMappingService deviceCodeMappingService) {
|
||||
public LinkStatusService(LinkTaskMapper linkTaskMapper, LinkBatchMapper linkBatchMapper,
|
||||
ScriptClient scriptClient, DeviceCodeMappingService deviceCodeMappingService) {
|
||||
this.linkTaskMapper = linkTaskMapper;
|
||||
this.linkBatchMapper = linkBatchMapper;
|
||||
this.scriptClient = scriptClient;
|
||||
this.deviceCodeMappingService = deviceCodeMappingService;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +95,6 @@ public class LinkStatusService {
|
||||
response.setQuantity(linkBatch.getQuantity());
|
||||
response.setTimes(linkBatch.getTimes());
|
||||
response.setTotalPoints(linkBatch.getQuantity() * linkBatch.getTimes());
|
||||
response.setRegion(linkTask.getRegion());
|
||||
response.setMachineId(linkTask.getMachineId());
|
||||
response.setLoginAt(linkTask.getLoginAt());
|
||||
response.setCreatedAt(linkTask.getCreatedAt());
|
||||
@@ -289,21 +291,27 @@ public class LinkStatusService {
|
||||
|
||||
UserLinkStatusResponse response = new UserLinkStatusResponse();
|
||||
response.setStatus("EXPIRED");
|
||||
response.setView("EXPIRED");
|
||||
return response;
|
||||
}
|
||||
|
||||
// 3. 根据状态执行相应逻辑
|
||||
// 3. 检查USING状态的10分钟过期逻辑
|
||||
if ("USING".equals(linkTask.getStatus())) {
|
||||
// 如果是USING状态,检查二维码是否过期,过期则刷新
|
||||
if (linkTask.getQrExpireAt() != null && linkTask.getQrExpireAt().isBefore(LocalDateTime.now())) {
|
||||
log.info("二维码已过期,执行自动刷新重置选区状态");
|
||||
performAutoRefresh(linkTask);
|
||||
} else {
|
||||
// 二维码还未过期,更新二维码信息
|
||||
log.info("链接状态是USING,重新获取二维码");
|
||||
updateQrCodeInfo(linkTask);
|
||||
// 检查是否超过10分钟未登录
|
||||
if (linkTask.getQrCreatedAt() != null &&
|
||||
linkTask.getQrCreatedAt().isBefore(LocalDateTime.now().minusMinutes(10))) {
|
||||
log.warn("选择设备已超过10分钟未登录,链接过期: qrCreatedAt={}", linkTask.getQrCreatedAt());
|
||||
linkTask.setStatus("EXPIRED");
|
||||
linkTask.setUpdatedAt(LocalDateTime.now());
|
||||
linkTaskMapper.update(linkTask);
|
||||
|
||||
UserLinkStatusResponse response = new UserLinkStatusResponse();
|
||||
response.setStatus("EXPIRED");
|
||||
return response;
|
||||
}
|
||||
|
||||
// 如果未超过10分钟,执行自动刷新
|
||||
log.info("链接状态是USING,执行自动刷新");
|
||||
performAutoRefresh(linkTask);
|
||||
} else if ("LOGGED_IN".equals(linkTask.getStatus()) || "REFUNDED".equals(linkTask.getStatus())) {
|
||||
// 已上号或已退款状态,不需要刷新
|
||||
log.info("链接状态为 {},不需要刷新", linkTask.getStatus());
|
||||
@@ -312,8 +320,7 @@ public class LinkStatusService {
|
||||
// 4. 构建响应
|
||||
UserLinkStatusResponse response = buildUserStatusResponse(linkTask);
|
||||
log.info("=== 用户端链接状态查询完成 ===");
|
||||
log.info("返回状态: {}, view: {}", response.getStatus(), response.getView());
|
||||
|
||||
log.info("返回状态: {}", response.getStatus());
|
||||
return response;
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -325,61 +332,23 @@ public class LinkStatusService {
|
||||
|
||||
/**
|
||||
* 执行自动刷新逻辑
|
||||
* 刷新时会重置选区状态,让用户重新选择区域
|
||||
* 只调用判断刷新接口,不更新数据库状态
|
||||
*/
|
||||
private void performAutoRefresh(LinkTask linkTask) {
|
||||
try {
|
||||
log.info("开始执行刷新操作,将重置选区状态");
|
||||
log.info("开始执行刷新操作");
|
||||
|
||||
// 1. 调用脚本端刷新
|
||||
String refreshResult = scriptClient.refresh(linkTask.getCodeNo()).block();
|
||||
log.info("脚本端刷新结果: {}", refreshResult);
|
||||
// 调用判断刷新接口(通过ScriptClient统一管理)
|
||||
String refreshResult = scriptClient.checkRefresh().block();
|
||||
log.info("判断刷新接口调用完成: result={}", refreshResult);
|
||||
|
||||
// 2. 重置选区状态,删除已有选区让用户重新选择
|
||||
log.info("重置选区状态: 从 {} 重置为 NEW", linkTask.getStatus());
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
linkTask.setStatus("NEW"); // 重置状态为NEW,允许重新选区
|
||||
linkTask.setRegion(null); // 清空已选择的区域
|
||||
linkTask.setQrCreatedAt(null); // 清空二维码创建时间
|
||||
linkTask.setQrExpireAt(null); // 清空二维码过期时间
|
||||
linkTask.setNeedRefresh(true); // 标记为刷新状态
|
||||
linkTask.setRefreshTime(now); // 记录刷新时间
|
||||
linkTask.setUpdatedAt(now); // 更新修改时间
|
||||
linkTaskMapper.update(linkTask);
|
||||
|
||||
log.info("选区状态重置完成: status=NEW, region=null, needRefresh=true");
|
||||
|
||||
// 3. 等待10秒后允许重新选区
|
||||
log.info("刷新完成,等待10秒后允许重新选区...");
|
||||
Thread.sleep(10000);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
log.warn("刷新等待被中断: {}", e.getMessage());
|
||||
} catch (Exception e) {
|
||||
log.warn("执行刷新操作失败: {}", e.getMessage());
|
||||
// 刷新失败不影响后续流程,但记录错误日志
|
||||
// 刷新失败不影响后续流程,只记录警告日志
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新二维码信息
|
||||
*/
|
||||
private void updateQrCodeInfo(LinkTask linkTask) {
|
||||
try {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
linkTask.setQrCreatedAt(now);
|
||||
linkTask.setQrExpireAt(now.plusSeconds(60)); // 60秒后过期
|
||||
linkTask.setUpdatedAt(now);
|
||||
linkTaskMapper.update(linkTask);
|
||||
|
||||
log.info("更新二维码信息成功: qrCreatedAt={}, qrExpireAt={}",
|
||||
linkTask.getQrCreatedAt(), linkTask.getQrExpireAt());
|
||||
} catch (Exception e) {
|
||||
log.warn("更新二维码信息失败: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 构建用户端状态响应
|
||||
@@ -387,58 +356,14 @@ public class LinkStatusService {
|
||||
private UserLinkStatusResponse buildUserStatusResponse(LinkTask linkTask) {
|
||||
UserLinkStatusResponse response = new UserLinkStatusResponse();
|
||||
|
||||
// 基本状态信息
|
||||
response.setStatus(linkTask.getStatus());
|
||||
response.setNeedRefresh(Boolean.TRUE.equals(linkTask.getNeedRefresh()));
|
||||
response.setRegion(linkTask.getRegion());
|
||||
|
||||
// 确定视图类型
|
||||
String view = determineView(linkTask.getStatus(), response.getNeedRefresh());
|
||||
response.setView(view);
|
||||
|
||||
// 如果状态是USING,设置二维码信息
|
||||
if ("USING".equals(linkTask.getStatus()) && linkTask.getQrCreatedAt() != null) {
|
||||
UserLinkStatusResponse.QrInfo qrInfo = new UserLinkStatusResponse.QrInfo();
|
||||
qrInfo.setUrl(scriptClient.getProxyQrCodeUrl(linkTask.getCodeNo()));
|
||||
qrInfo.setCreatedAt(java.sql.Timestamp.valueOf(linkTask.getQrCreatedAt()).getTime());
|
||||
if (linkTask.getQrExpireAt() != null) {
|
||||
qrInfo.setExpireAt(java.sql.Timestamp.valueOf(linkTask.getQrExpireAt()).getTime());
|
||||
}
|
||||
response.setQr(qrInfo);
|
||||
}
|
||||
|
||||
// 如果状态是LOGGED_IN,设置资源信息
|
||||
if ("LOGGED_IN".equals(linkTask.getStatus())) {
|
||||
UserLinkStatusResponse.AssetsInfo assets = new UserLinkStatusResponse.AssetsInfo();
|
||||
assets.setBase(String.format("http://36.138.184.60:12345/%s/", linkTask.getCodeNo()));
|
||||
assets.setFirstHome("首次主页.png");
|
||||
assets.setFirstBonus("首次赏金.png");
|
||||
assets.setMidBonus("中途赏金.png");
|
||||
assets.setEndBonus("结束赏金.png");
|
||||
response.setAssets(assets);
|
||||
}
|
||||
// 如果状态是USING,返回NEW给用户端
|
||||
String statusToReturn = "USING".equals(linkTask.getStatus()) ? "NEW" : linkTask.getStatus();
|
||||
response.setStatus(statusToReturn);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* 确定视图类型
|
||||
*/
|
||||
private String determineView(String status, boolean needRefresh) {
|
||||
switch (status) {
|
||||
case "NEW":
|
||||
return needRefresh ? "REFRESH" : "FIRST";
|
||||
case "USING":
|
||||
return "SCAN";
|
||||
case "LOGGED_IN":
|
||||
return "SECOND";
|
||||
case "REFUNDED":
|
||||
case "EXPIRED":
|
||||
return "EXPIRED";
|
||||
default:
|
||||
return "FIRST";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 选区操作
|
||||
@@ -471,6 +396,14 @@ public class LinkStatusService {
|
||||
log.info("查询到链接任务: id={}, codeNo={}, status={}, needRefresh={}",
|
||||
linkTask.getId(), linkTask.getCodeNo(), linkTask.getStatus(), linkTask.getNeedRefresh());
|
||||
|
||||
// 查询批次信息获取times参数
|
||||
LinkBatch linkBatch = linkBatchMapper.findById(linkTask.getBatchId());
|
||||
if (linkBatch == null) {
|
||||
log.error("批次信息不存在: batchId={}", linkTask.getBatchId());
|
||||
throw new IllegalStateException("批次信息不存在");
|
||||
}
|
||||
log.info("查询到批次信息: batchId={}, times={}", linkBatch.getId(), linkBatch.getTimes());
|
||||
|
||||
// 3. 检查链接状态,只有NEW状态才能选区
|
||||
if (!"NEW".equals(linkTask.getStatus())) {
|
||||
log.error("链接状态不正确,无法选区: status={}", linkTask.getStatus());
|
||||
@@ -509,29 +442,42 @@ public class LinkStatusService {
|
||||
deviceStatus.getTotalDevices(), deviceStatus.getAvailableCount(), deviceStatus.getAvailableDevices());
|
||||
|
||||
// 7. 选择一个空闲设备
|
||||
String selectedDevice = deviceStatus.getAvailableDevices().get(0); // 选择第一个空闲设备
|
||||
log.info("选择设备: {}", selectedDevice);
|
||||
// String selectedDevice = deviceStatus.getAvailableDevices().get(0); // 选择第一个空闲设备
|
||||
String selectedDevice = "cc2";
|
||||
log.info("从空闲设备列表中选择设备: {}", selectedDevice);
|
||||
log.info("设备选择详情: 可用设备总数={}, 选择了第一个设备={}",
|
||||
deviceStatus.getAvailableDevices().size(), selectedDevice);
|
||||
|
||||
// 8. 为选中的设备创建代理code
|
||||
// 8. 调用保存总次数接口
|
||||
try {
|
||||
scriptClient.saveTotalTimes(linkBatch.getTimes()).block();
|
||||
// saveTotalTimes方法已经包含了详细的日志记录
|
||||
} catch (Exception e) {
|
||||
log.warn("保存总次数接口调用失败: {}", e.getMessage());
|
||||
// 不影响后续流程,只记录警告日志
|
||||
}
|
||||
|
||||
// 9. 为选中的设备创建代理code
|
||||
String proxyCode = deviceCodeMappingService.createProxyCode(selectedDevice);
|
||||
log.info("为设备 {} 创建代理code: {}", selectedDevice, proxyCode);
|
||||
|
||||
// 9. 调用脚本端选区,使用选中的设备
|
||||
// 10. 调用脚本端选区,使用选中的设备
|
||||
log.info("开始调用脚本端选区,设备={}, 区域={}", selectedDevice, region);
|
||||
String selectResult = scriptClient.selectRegion(selectedDevice, region).block();
|
||||
log.info("脚本端选区结果: {}", selectResult);
|
||||
|
||||
// 10. 等待脚本端生成二维码(这里可以添加轮询逻辑)
|
||||
// 11. 等待脚本端生成二维码(这里可以添加轮询逻辑)
|
||||
log.info("等待脚本端生成二维码,等待3秒...");
|
||||
Thread.sleep(3000);
|
||||
|
||||
// 11. 更新数据库状态为USING,保存设备信息和代理code
|
||||
// 12. 更新数据库状态为USING,保存设备信息和代理code
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
linkTask.setStatus("USING");
|
||||
linkTask.setRegion(region);
|
||||
linkTask.setCodeNo(proxyCode); // 使用代理code替换原来的codeNo
|
||||
linkTask.setQrCreatedAt(now);
|
||||
linkTask.setQrExpireAt(now.plusSeconds(60)); // 60秒后过期
|
||||
linkTask.setFirstRegionSelectAt(now); // 记录首次选区时间
|
||||
linkTask.setNeedRefresh(false);
|
||||
linkTask.setUpdatedAt(now);
|
||||
// 在machineId字段保存真实设备编号,便于调试和维护
|
||||
@@ -540,13 +486,13 @@ public class LinkStatusService {
|
||||
|
||||
log.info("链接状态更新成功: status=USING, region={}, proxyCode={}, device={}", region, proxyCode, selectedDevice);
|
||||
|
||||
// 12. 构建响应
|
||||
// 13. 构建响应
|
||||
SelectRegionResponse response = new SelectRegionResponse(true, "选区成功");
|
||||
response.setQrCodeUrl(scriptClient.getProxyQrCodeUrl(proxyCode));
|
||||
response.setQrCreatedAt(now);
|
||||
response.setQrExpireAt(linkTask.getQrExpireAt());
|
||||
response.setStatus("USING");
|
||||
response.setRegion(region);
|
||||
// 不返回选区字段:response.setRegion(region);
|
||||
response.setQrDelaySeconds(5); // 客户端收到响应后,等待5秒再请求二维码
|
||||
|
||||
log.info("=== 选区操作完成 ===");
|
||||
|
||||
Reference in New Issue
Block a user