feat: 添加用户端链接状态查询接口及自动刷新逻辑
主要修改: 1. 在LinkController中新增获取用户链接状态的接口,支持通过linkId或codeNo查询。 2. 在LinkStatusService中实现用户链接状态查询逻辑,包含自动刷新和二维码更新功能。 3. 更新LinkTask实体,添加needRefresh、refreshTime、qrCreatedAt和qrExpireAt字段以支持新功能。 4. 在ScriptClient中新增检查空闲设备、选区、刷新、检查上号状态等操作的实现。 5. 更新SecurityConfig,允许用户端获取链接状态接口公开访问。 技术细节: - 新增UserLinkStatusResponse DTO以支持用户链接状态的返回格式。 - 通过脚本端接口实现链接状态的自动刷新和二维码信息更新。
This commit is contained in:
@@ -55,6 +55,110 @@ public class ScriptClient {
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.doOnError(e -> log.warn("ScriptClient.getText error path={} err={}", path, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查空闲设备
|
||||
*/
|
||||
public Mono<String> checkAvailableDevice() {
|
||||
String url = "http://36.138.184.60:1234/yijianwan_netfile/readAllMsg?文件名=判断分数";
|
||||
log.debug("检查空闲设备: {}", url);
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> log.debug("检查空闲设备成功: {}", result))
|
||||
.doOnError(e -> log.warn("检查空闲设备失败: {}", e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 选区操作
|
||||
*/
|
||||
public Mono<String> selectRegion(String codeNo, String region) {
|
||||
String url = String.format("http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断系统&编号=%s", region);
|
||||
log.debug("选区操作: codeNo={}, region={}, url={}", codeNo, region, url);
|
||||
return webClient.post()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> log.debug("选区操作成功: codeNo={}, region={}, result={}", codeNo, region, result))
|
||||
.doOnError(e -> log.warn("选区操作失败: codeNo={}, region={}, error={}", codeNo, region, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新操作
|
||||
*/
|
||||
public Mono<String> refresh(String codeNo) {
|
||||
String url = "http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=判断刷新&编号=刷新";
|
||||
log.debug("刷新操作: codeNo={}, url={}", codeNo, url);
|
||||
return webClient.post()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> log.debug("刷新操作成功: codeNo={}, result={}", codeNo, result))
|
||||
.doOnError(e -> log.warn("刷新操作失败: codeNo={}, error={}", codeNo, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查上号状态
|
||||
*/
|
||||
public Mono<String> checkLoginStatus(String codeNo) {
|
||||
String url = String.format("http://36.138.184.60:1234/yijianwan_netfile/readMsg?文件名=判断上号&对象名=%s", codeNo);
|
||||
log.debug("检查上号状态: codeNo={}, url={}", codeNo, url);
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.doOnSuccess(result -> log.debug("检查上号状态成功: codeNo={}, result={}", codeNo, result))
|
||||
.doOnError(e -> log.warn("检查上号状态失败: codeNo={}, error={}", codeNo, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取二维码URL(带时间戳防缓存)
|
||||
*/
|
||||
public String getQrCodeUrl(String codeNo) {
|
||||
long timestamp = System.currentTimeMillis();
|
||||
return String.format("http://36.138.184.60:12345/%s/二维码.png?t=%d", codeNo, timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取目标分数
|
||||
*/
|
||||
public Mono<String> getTargetScore(String codeNo) {
|
||||
String url = String.format("http://36.138.184.60:1234/yijianwan_netfile/readMsg?文件名=判断分数&对象名=%s", codeNo);
|
||||
log.debug("获取目标分数: codeNo={}, url={}", codeNo, url);
|
||||
return webClient.get()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(5))
|
||||
.doOnSuccess(result -> log.debug("获取目标分数成功: codeNo={}, result={}", codeNo, result))
|
||||
.doOnError(e -> log.warn("获取目标分数失败: codeNo={}, error={}", codeNo, e.toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置次数(生成链接时调用)
|
||||
*/
|
||||
public Mono<String> setTimes(String codeNo, int times) {
|
||||
String url = String.format("http://36.138.184.60:1234/yijianwan_netfile/saveMsg?文件名=总次数&编号=%d", times);
|
||||
log.debug("设置次数: codeNo={}, times={}, url={}", codeNo, times, url);
|
||||
return webClient.post()
|
||||
.uri(url)
|
||||
.accept(MediaType.TEXT_PLAIN)
|
||||
.retrieve()
|
||||
.bodyToMono(String.class)
|
||||
.timeout(Duration.ofSeconds(10))
|
||||
.doOnSuccess(result -> log.debug("设置次数成功: codeNo={}, times={}, result={}", codeNo, times, result))
|
||||
.doOnError(e -> log.warn("设置次数失败: codeNo={}, times={}, error={}", codeNo, times, e.toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -4,8 +4,11 @@ import com.gameplatform.server.mapper.agent.LinkBatchMapper;
|
||||
import com.gameplatform.server.mapper.agent.LinkTaskMapper;
|
||||
import com.gameplatform.server.model.dto.link.BatchDeleteResponse;
|
||||
import com.gameplatform.server.model.dto.link.LinkStatusResponse;
|
||||
import com.gameplatform.server.model.dto.link.UserLinkStatusResponse;
|
||||
import com.gameplatform.server.model.entity.agent.LinkBatch;
|
||||
import com.gameplatform.server.model.entity.agent.LinkTask;
|
||||
|
||||
import com.gameplatform.server.service.external.ScriptClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -28,6 +31,8 @@ public class LinkStatusService {
|
||||
private final LinkTaskMapper linkTaskMapper;
|
||||
private final LinkBatchMapper linkBatchMapper;
|
||||
|
||||
private final ScriptClient scriptClient;
|
||||
|
||||
// 状态描述映射
|
||||
private static final Map<String, String> STATUS_DESC_MAP = new HashMap<>();
|
||||
static {
|
||||
@@ -38,9 +43,11 @@ public class LinkStatusService {
|
||||
STATUS_DESC_MAP.put("EXPIRED", "已过期");
|
||||
}
|
||||
|
||||
public LinkStatusService(LinkTaskMapper linkTaskMapper, LinkBatchMapper linkBatchMapper) {
|
||||
public LinkStatusService(LinkTaskMapper linkTaskMapper, LinkBatchMapper linkBatchMapper,
|
||||
ScriptClient scriptClient) {
|
||||
this.linkTaskMapper = linkTaskMapper;
|
||||
this.linkBatchMapper = linkBatchMapper;
|
||||
this.scriptClient = scriptClient;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,4 +243,181 @@ public class LinkStatusService {
|
||||
return response;
|
||||
}).subscribeOn(Schedulers.boundedElastic());
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户端获取链接状态(支持linkId或codeNo参数,带自动刷新逻辑)
|
||||
*/
|
||||
public Mono<UserLinkStatusResponse> getUserLinkStatus(Long linkId, String codeNo) {
|
||||
return Mono.fromCallable(() -> doGetUserLinkStatus(linkId, codeNo))
|
||||
.subscribeOn(Schedulers.boundedElastic());
|
||||
}
|
||||
|
||||
private UserLinkStatusResponse doGetUserLinkStatus(Long linkId, String codeNo) {
|
||||
log.info("=== 开始处理用户端链接状态查询 ===");
|
||||
log.info("linkId: {}, codeNo: {}", linkId, codeNo);
|
||||
|
||||
try {
|
||||
// 1. 查询链接任务
|
||||
LinkTask linkTask = null;
|
||||
if (linkId != null) {
|
||||
linkTask = linkTaskMapper.findById(linkId);
|
||||
log.info("通过linkId查询链接任务: id={}", linkId);
|
||||
} else if (codeNo != null && !codeNo.trim().isEmpty()) {
|
||||
linkTask = linkTaskMapper.findByCodeNo(codeNo.trim());
|
||||
log.info("通过codeNo查询链接任务: codeNo={}", codeNo);
|
||||
}
|
||||
|
||||
if (linkTask == null) {
|
||||
log.error("链接任务不存在: linkId={}, codeNo={}", linkId, codeNo);
|
||||
throw new IllegalArgumentException("链接不存在");
|
||||
}
|
||||
|
||||
log.info("查询到链接任务: id={}, codeNo={}, status={}, needRefresh={}",
|
||||
linkTask.getId(), linkTask.getCodeNo(), linkTask.getStatus(), linkTask.getNeedRefresh());
|
||||
|
||||
// 2. 检查链接任务是否过期
|
||||
if (linkTask.getExpireAt() != null && linkTask.getExpireAt().isBefore(LocalDateTime.now())) {
|
||||
log.warn("链接任务已过期: expireAt={}", linkTask.getExpireAt());
|
||||
linkTask.setStatus("EXPIRED");
|
||||
linkTask.setUpdatedAt(LocalDateTime.now());
|
||||
linkTaskMapper.update(linkTask);
|
||||
|
||||
UserLinkStatusResponse response = new UserLinkStatusResponse();
|
||||
response.setStatus("EXPIRED");
|
||||
response.setView("EXPIRED");
|
||||
return response;
|
||||
}
|
||||
|
||||
// 3. 如果状态不是NEW,执行自动刷新逻辑
|
||||
if (!"NEW".equals(linkTask.getStatus())) {
|
||||
log.info("链接状态不是NEW,执行自动刷新逻辑");
|
||||
performAutoRefresh(linkTask);
|
||||
}
|
||||
|
||||
// 4. 如果状态是USING,重新获取二维码
|
||||
if ("USING".equals(linkTask.getStatus())) {
|
||||
log.info("链接状态是USING,重新获取二维码");
|
||||
updateQrCodeInfo(linkTask);
|
||||
}
|
||||
|
||||
// 5. 构建响应
|
||||
UserLinkStatusResponse response = buildUserStatusResponse(linkTask);
|
||||
log.info("=== 用户端链接状态查询完成 ===");
|
||||
log.info("返回状态: {}, view: {}", response.getStatus(), response.getView());
|
||||
|
||||
return response;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("=== 用户端链接状态查询失败 ===");
|
||||
log.error("错误详情: {}", e.getMessage(), e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行自动刷新逻辑
|
||||
*/
|
||||
private void performAutoRefresh(LinkTask linkTask) {
|
||||
try {
|
||||
log.info("开始执行刷新操作");
|
||||
|
||||
// 调用脚本端刷新
|
||||
String refreshResult = scriptClient.refresh(linkTask.getCodeNo()).block();
|
||||
log.info("脚本端刷新结果: {}", refreshResult);
|
||||
|
||||
// 更新刷新状态
|
||||
linkTask.setNeedRefresh(true);
|
||||
linkTask.setRefreshTime(LocalDateTime.now());
|
||||
linkTask.setUpdatedAt(LocalDateTime.now());
|
||||
linkTaskMapper.update(linkTask);
|
||||
|
||||
// 等待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());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建用户端状态响应
|
||||
*/
|
||||
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.getQrCodeUrl(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);
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user