package modules.nftt; import com.alibaba.fastjson.JSONObject; import com.jfinal.kit.StrKit; import common.jfinal.AppConfig; import common.model.Nftt; import common.utils.bsn.BsnSDK; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.concurrent.TimeUnit; public class NfttStatusMaintenanceTask implements Runnable { private static final Logger LOGGER = LoggerFactory.getLogger(NfttStatusMaintenanceTask.class); // 任务是否应该停止的标志 private volatile boolean running = true; // 使用 volatile 确保多线程可见性 public NfttStatusMaintenanceTask() { LOGGER.info("NftStatusMaintenanceTask 实例已创建。"); } @Override public void run() { LOGGER.info("NftStatusMaintenanceTask 后台任务开始运行..."); while (running) { // 循环直到收到停止指令 try { // 每次循环后休眠一段时间,避免CPU空转,并控制检查频率 Thread.sleep(TimeUnit.SECONDS.toMillis(10)); // 每 10 秒检查一次 // 只处理已支付但未确权的 String sql = "SELECT * FROM t_nftt WHERE bsn_token_id IS NULL"; flushNftStatus(Nftt.dao.find(sql)); } catch (InterruptedException e) { LOGGER.warn("NftStatusMaintenanceTask 因中断而停止。"); Thread.currentThread().interrupt(); // 重新设置中断状态 running = false; // 退出循环 } catch (Exception e) { // 捕获所有其他异常,记录日志,但保持线程继续运行 LOGGER.error("NftStatusMaintenanceTask 执行异常: {}", e.getMessage(), e); // 可以在这里添加告警,或在短时间后重试 try { Thread.sleep(TimeUnit.SECONDS.toMillis(5)); // 发生错误时短暂休眠,避免错误日志刷屏 } catch (InterruptedException ie) { Thread.currentThread().interrupt(); running = false; } } } LOGGER.info("NftStatusMaintenanceTask 后台任务已停止运行。"); } private void flushNftStatus(List list) throws InterruptedException { // 遍历列表,处理 BSN 状态更新逻辑 // 这个逻辑会影响分页查询的性能,特别是当 BsnSDK.search 是耗时操作时 // 建议将其移到异步处理或专门的同步任务中 for (Nftt nftt : list) { // bsnTokenId 如果不为空,说明已经处理过上链结果,跳过 if (StrKit.notBlank(nftt.getBsnTokenId())) { continue; } try { // 调用 BSN SDK 查询上链状态 // 确保 BsnSDK.search 返回的是 JSONObject,且参数正确 JSONObject searchObject = BsnSDK.search("DLTBH_NFT_" + nftt.getLong("id")); // 假设 id 是 Long 类型 // 记录原始响应,便于调试 nftt.set("bsn_status_json", searchObject.toJSONString()); // 假设字段名为 bsn_status_json // 不需要在这里立即 update(),可以在最后处理完所有状态后再批量更新,或在成功时更新 // nftt.update(); // 暂时移除,避免频繁更新 // 校验 BSN SDK 响应 if (searchObject.getInteger("code") == null || searchObject.getInteger("code") != 0) { throw new RuntimeException("BSN API查询失败,返回值与预期不符或code不为0:" + searchObject.toJSONString()); } JSONObject data = searchObject.getJSONObject("data"); if (data == null) { throw new RuntimeException("BSN API响应数据为空:" + searchObject.toJSONString()); } Integer status = data.getInteger("status"); if (status == null) { throw new RuntimeException("BSN API响应状态字段缺失:" + searchObject.toJSONString()); } if (status == 2) { // 假设 status == 2 表示上链失败 nftt.set("bsn_token_id", "-1"); // 标记上链失败 nftt.set("bsn_status_json", searchObject.toJSONString()); // 更新失败状态信息 nftt.update(); // 立即更新失败状态 throw new RuntimeException("BSN 上链失败,链上的错误:" + searchObject.toJSONString()); } if (status == 1) { // 假设 status == 1 表示上链成功且有 tokenId String tokenId = data.getString("tokenId"); if (StrKit.isBlank(tokenId)) { throw new RuntimeException("BSN 上链成功但 tokenId 为空:" + searchObject.toJSONString()); } nftt.set("bsn_token_id", tokenId); nftt.set("bsn_status_json", searchObject.toJSONString()); // 更新成功状态信息 nftt.update(); // 立即更新成功状态 AppConfig.LOGGER.error("查询并更新NFT {} 的BSN状态成功{}", nftt.getLong("id"), searchObject); } // 如果 status 是其他值,可能表示正在处理中,不更新 bsn_token_id } catch (Exception e) { // 记录错误日志,但通常不应该影响整个列表的返回 AppConfig.LOGGER.error("查询并更新NFT {} 的BSN状态时出现问题:{}", nftt.getLong("id"), e.getMessage(), e); // 这里可以选择不throw,或者throw RuntimeException让上层捕获 // 如果是服务故障,可能需要全局捕获并告警 } } } }