租赁系统

This commit is contained in:
yyb
2026-01-05 15:46:59 +08:00
parent 61fa33c27c
commit 5559163b2e
385 changed files with 33178 additions and 0 deletions

View File

@@ -0,0 +1,197 @@
package com.m2pool.lease.task;
import cn.hutool.http.HttpRequest;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.m2pool.lease.constant.BlockInterval;
import com.m2pool.lease.entity.LeaseGpuConfig;
import com.m2pool.lease.entity.LeaseMiningSoftwareConfig;
import com.m2pool.lease.mapper.LeaseGpuConfigMapper;
import com.m2pool.lease.mapper.LeaseMiningSoftwareConfigMapper;
import com.m2pool.lease.task.info.*;
import io.lettuce.core.ScriptOutputType;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
/**
* @Description 获取gpu 信息三方apiwhattomine.com 定时任务
* @Date 2025/12/16 15:38
* @Author yyb
*/
@Configuration
@EnableScheduling
public class GpuRequestApiTask {
@Resource
private LeaseGpuConfigMapper leaseGpuConfigMapper;
@Resource
private LeaseMiningSoftwareConfigMapper leaseMiningSoftwareConfigMapper;
@Scheduled(cron = "0 0 0/6 * * ? ")
//@Scheduled(cron = "0 0/5 * * * ? ")
public void gpuInfoTask(){
List<GpuInfo> gpuInfos = fetchGpuInfo();
List<LeaseGpuConfig> leaseGpuConfigs = convertGpuInfoToLeaseConfig(gpuInfos);
List<LeaseMiningSoftwareConfig> leaseMiningSoftwareConfigs = leaseMiningSoftwareConfigMapper.
selectList(new LambdaQueryWrapper<>());
//选出挖矿软件只支持的算法和币种
List<LeaseGpuConfig> leaseGpuConfigs1 = new ArrayList<>();
for (LeaseGpuConfig leaseGpuConfig : leaseGpuConfigs) {
for (LeaseMiningSoftwareConfig leaseMiningSoftwareConfig : leaseMiningSoftwareConfigs) {
if (leaseMiningSoftwareConfig.getAlgorithm().contains(leaseGpuConfig.getAlgorithm())){
leaseGpuConfig.setCoin(leaseMiningSoftwareConfig.getCoin());
leaseGpuConfigs1.add(leaseGpuConfig);
break;
}
}
}
List<AlgorithmInfo> coinNetPowers = fetchMiningPower();
if (!coinNetPowers.isEmpty()){
Map<String, AlgorithmInfo> coinPowerMap = coinNetPowers.stream()
.collect(Collectors.toMap(AlgorithmInfo-> AlgorithmInfo.getCoin()+"-"+AlgorithmInfo.getName(), Function.identity()));
for (LeaseGpuConfig leaseGpuConfig : leaseGpuConfigs1) {
AlgorithmInfo coinPower = coinPowerMap.get(leaseGpuConfig.getCoin()+"-"+leaseGpuConfig.getAlgorithm());
BigDecimal monthIncome = calculateMonthIncome(leaseGpuConfig, coinPower);
leaseGpuConfig.setMonthIncome(monthIncome);
}
}
leaseGpuConfigMapper.insertOrUpdateBatchByEntity(leaseGpuConfigs1);
}
/**
* 计算月收入
* @param leaseGpuConfig
* @param coinPower
* @return
*/
private static BigDecimal calculateMonthIncome(LeaseGpuConfig leaseGpuConfig, AlgorithmInfo coinPower) {
BigDecimal monthIncome = BigDecimal.ZERO;
if (coinPower != null){
monthIncome = leaseGpuConfig.getHashrate()
.divide(coinPower.getHashrate().divide(BigDecimal.valueOf(1000 * 1000), 8, RoundingMode.HALF_UP), 8, RoundingMode.HALF_UP)
.multiply(BigDecimal.valueOf(24 * 60 * 60)
.divide(coinPower.getBlockInterval(), 8, RoundingMode.HALF_UP))
.multiply(coinPower.getBlockReward()).multiply(BigDecimal.valueOf(30))
.multiply(coinPower.getPrice())
;
}
return monthIncome;
}
/**
* 三方api 获取gpu信息
* @return
*/
public List<GpuInfo> fetchGpuInfo() {
String url = "https://whattomine.com/api/v1/gpus?api_token=8ea12738081eaa70a37d62364ddfffecc0c96a6047f02b4cc728af7588fcdbd8";
String response = HttpRequest.get(url).execute().body();
// 将JSONUtil.parseArray改为JSON.parseArray
JSONArray gpusArray = JSON.parseArray(response);
List<GpuInfo> gpuInfoList = new ArrayList<>();
for (Object obj : gpusArray) {
// JSONObject转换方式
JSONObject gpuJson = (JSONObject) obj;
GpuInfo gpuInfo = new GpuInfo();
// 设置基本GPU信息
gpuInfo.setId(gpuJson.getLong("id"));
gpuInfo.setName(gpuJson.getString("name"));
gpuInfo.setRelease_date(gpuJson.getString("release_date"));
// 处理算法信息
JSONArray algorithmsArray = gpuJson.getJSONArray("algorithms");
List<AlgorithmInfo> algorithmInfos = new ArrayList<>();
for (Object algoObj : algorithmsArray) {
// JSONObject转换方式
JSONObject algoJson = (JSONObject) algoObj;
AlgorithmInfo algorithmInfo = new AlgorithmInfo();
algorithmInfo.setName(algoJson.getString("name"));
algorithmInfo.setHashrate(algoJson.getBigDecimal("hashrate"));
algorithmInfo.setPower(algoJson.getBigDecimal("power"));
algorithmInfos.add(algorithmInfo);
}
gpuInfo.setAlgorithms(algorithmInfos);
gpuInfoList.add(gpuInfo);
}
return gpuInfoList;
}
public List<LeaseGpuConfig> convertGpuInfoToLeaseConfig(List<GpuInfo> gpuInfos) {
List<LeaseGpuConfig> leaseGpuConfigs = new ArrayList<>();
for (GpuInfo gpuInfo : gpuInfos) {
if (gpuInfo.getAlgorithms() != null) {
for (AlgorithmInfo algorithm : gpuInfo.getAlgorithms()) {
LeaseGpuConfig config = buildGpuConfig(gpuInfo, algorithm);
leaseGpuConfigs.add(config);
}
}
}
return leaseGpuConfigs;
}
private static LeaseGpuConfig buildGpuConfig(GpuInfo gpuInfo, AlgorithmInfo algorithm) {
LeaseGpuConfig config = new LeaseGpuConfig();
config.setName(gpuInfo.getName());
config.setAlgorithm(algorithm.getName());
config.setHashrate(algorithm.getHashrate().divide(BigDecimal.valueOf(1000 * 1000),2, RoundingMode.HALF_UP));
config.setPowerDissipation(algorithm.getPower());
return config;
}
/**
* 三方api 获取gpu 对应算法的收益信息
* @return
*/
public static List<AlgorithmInfo> fetchMiningPower() {
String url = "https://whattomine.com/api/v1/coins?api_token=8ea12738081eaa70a37d62364ddfffecc0c96a6047f02b4cc728af7588fcdbd8";
String response = HttpRequest.get(url).execute().body();
JSONArray gpusArray = JSON.parseArray(response);
List<AlgorithmInfo> hashRateInfos = new ArrayList<>();
for (int i = 0; i < gpusArray.size(); i++) {
JSONObject item = gpusArray.getJSONObject(i);
AlgorithmInfo info = new AlgorithmInfo();
info.setCoin(item.getString("tag"));
info.setName(item.getString("algorithm"));
info.setHashrate(new BigDecimal(item.getLong("nethash")));
info.setBlockReward(BigDecimal.valueOf(item.getDouble("block_reward")));
info.setBlockInterval(BigDecimal.valueOf(item.getDouble("block_time")));
// 解析exchanges数组并获取第一个对象的price值
JSONArray exchanges = item.getJSONArray("exchanges");
if (!exchanges.isEmpty()) {
JSONObject firstExchange = exchanges.getJSONObject(0);
//30日平均币价
info.setPrice(BigDecimal.valueOf(firstExchange.getDouble("price30")).multiply(BigDecimal.valueOf(100000)));
}
hashRateInfos.add(info);
}
return hashRateInfos;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,324 @@
package com.m2pool.lease.task;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.m2pool.lease.dto.HourIncomeDto;
import com.m2pool.lease.dto.OrderStatusDto;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.mq.message.RabbitmqPoolProxyMessage;
import com.m2pool.lease.service.LeaseOrderInfoService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.rmi.dgc.Lease;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.m2pool.lease.constant.RabbitmqConstant.POOL_PROXY_QUEUE_NAME;
/**
* @Description 后台管理系统 定时任务
* @Date 2025/7/15 15:45
* @Author yyb
*/
@Configuration
@EnableScheduling
public class OwnProductTask {
@Resource
private LeaseUserOwnedProductMapper leaseUserOwnedProductMapper;
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
@Resource
private LeaseOrderItemMapper leaseOrderItemMapper;
@Resource
private LeaseOrderInfoService leaseOrderInfoService;
@Resource
private LeasePayRecordMessageMapper leasePayRecordMessageMapper;
@Resource
private RabbitTemplate rabbitTemplate;
private static final int THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors();
private static final int BATCH_SIZE = 1000;
private final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
/**
* 修改已购表租约过期状态为1 已过期 + 机器表状态为0 未售出 + 修改租约到期订单状态为已完成
*/
@Scheduled(cron = "0 1,5,7 0 * * ? ")
//@Scheduled(cron = "0 0/3 * * * ? ")
@Transactional
public void updateOwnMachineStateTask(){
// 获取当天 0 点的 LocalDateTime
LocalDateTime now = LocalDateTime.now();
LocalDateTime startOfDay = now.toLocalDate().atStartOfDay();
//1. 查询当天失效机器
LambdaQueryWrapper<LeaseUserOwnedProduct> wrapper = new LambdaQueryWrapper<LeaseUserOwnedProduct>()
.eq(LeaseUserOwnedProduct::getEndTime, startOfDay).eq(LeaseUserOwnedProduct::getStatus, 0);
List<LeaseUserOwnedProduct> leaseUserOwnedProducts = leaseUserOwnedProductMapper.selectList(wrapper);
if (!leaseUserOwnedProducts.isEmpty()){
//2.修改商品机器表中 销售状态为 0 未售出
List<Long> ids = new ArrayList<>();
List<Long> isExpireIds = new ArrayList<>();
List<Long> itemIds = new ArrayList<>();
for (LeaseUserOwnedProduct leaseUserOwnedProduct : leaseUserOwnedProducts) {
ids.add(leaseUserOwnedProduct.getId());
isExpireIds.add(leaseUserOwnedProduct.getProductMachineId());
itemIds.add(leaseUserOwnedProduct.getOrderItemId());
}
leaseUserOwnedProductMapper.update(LeaseUserOwnedProduct.builder().status(1).build(),new LambdaUpdateWrapper<LeaseUserOwnedProduct>()
.in(LeaseUserOwnedProduct::getId, ids));
leaseProductMachineMapper.update(LeaseProductMachine.builder().saleState(0).build(),
new LambdaQueryWrapper<LeaseProductMachine>().in(LeaseProductMachine::getId, isExpireIds));
leaseOrderItemMapper.update(LeaseOrderItem.builder().status(0).build(),new LambdaQueryWrapper<LeaseOrderItem>().in(LeaseOrderItem::getId, itemIds));
//3.订单所有机器已过期,直接修改订单状态为已完成
List<Long> orderIds = leaseOrderItemMapper.getOrderIds(itemIds);
List<OrderStatusDto> orderInfoStatus = leaseOrderItemMapper.getOrderInfoStatus(orderIds);
List<LeaseOrderInfo> infoList = new ArrayList<>();
orderInfoStatus.forEach(item->{
if (item.getOrderInfoStatus() == 8){
infoList.add(LeaseOrderInfo.builder().id(item.getOrderId()).status(8).build());
}
});
if (!infoList.isEmpty()){
leaseOrderInfoService.saveOrUpdateBatch(infoList);
}
System.out.println("租约过期机器状态修改成功");
//3.发送rabbitmq消息给矿池代理删除代理的矿机
//sendRabbitmqMessage(leaseUserOwnedProducts);
}
}
public void sendRabbitmqMessage( List<LeaseUserOwnedProduct> leaseUserOwnedProducts) {
leaseUserOwnedProducts.forEach(item -> {
executorService.execute(()->{
RabbitmqPoolProxyMessage rabbitmqPoolProxyMessage = RabbitmqPoolProxyMessage.builder()
.MethodID(1)
.Msg("")
.ID(item.getUser() + "-" + item.getMiner())
.Address(item.getAddress())
.build();
try {
rabbitTemplate.convertAndSend(POOL_PROXY_QUEUE_NAME, rabbitmqPoolProxyMessage);
//同步阻塞等待消息发送成功
//boolean b = rabbitTemplate.waitForConfirms(10000);
} catch (Exception e) {
System.err.println("发送失败: " + e.getMessage());
}
});
});
}
@Scheduled(cron = "0 35 0/1 * * ? ")
//@Scheduled(cron = "30 0/2 * * * ? ")
@DSTransactional
public void updateNexaIncomeTask(){
List<LeaseUserOwnedProduct> updateList = computeIncome("nexa");
//批量修改
batchUpdateLeaseUserOwnedProducts(updateList);
}
@Scheduled(cron = "10 35 0/1 * * ? ")
//@Scheduled(cron = "30 0/2 * * * ? ")
@DSTransactional
public void updateGrsIncomeTask(){
List<LeaseUserOwnedProduct> updateList = computeIncome("grs");
//批量修改
batchUpdateLeaseUserOwnedProducts(updateList);
}
@Scheduled(cron = "20 35 0/1 * * ? ")
//@Scheduled(cron = "30 0/2 * * * ? ")
@DSTransactional
public void updateRxdIncomeTask(){
List<LeaseUserOwnedProduct> updateList = computeIncome("rxd");
//批量修改
batchUpdateLeaseUserOwnedProducts(updateList);
}
@Scheduled(cron = "30 35 0/1 * * ? ")
//@Scheduled(cron = "30 0/2 * * * ? ")
@DSTransactional
public void updateMonaIncomeTask(){
List<LeaseUserOwnedProduct> updateList = computeIncome("mona");
//批量修改
batchUpdateLeaseUserOwnedProducts(updateList);
}
/**
* 计算已购生效机器过去一小时收益
* @param coin
*/
public List<LeaseUserOwnedProduct> computeIncome(String coin){
//获取当前时间整点时间
LocalDateTime now = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
//获取当天开始时间
//LocalDateTime startOfDay = now.with(LocalTime.MIN);
LocalDateTime end = now.minusHours(1);
LocalDateTime start = now.minusHours(2);
//1. 查询在有效期内的已购机器
LambdaQueryWrapper<LeaseUserOwnedProduct> wrapper = new LambdaQueryWrapper<LeaseUserOwnedProduct>()
.eq(LeaseUserOwnedProduct::getCoin, coin)
.eq(LeaseUserOwnedProduct::getStatus, 0);
List<LeaseUserOwnedProduct> leaseUserOwnedProducts = leaseUserOwnedProductMapper.selectList(wrapper);
//2.获取近一个小时矿机的收益 + 并计算实时收益
List<LeaseUserOwnedProduct> updateList = new ArrayList<>();
if (!leaseUserOwnedProducts.isEmpty()){
List<HourIncomeDto> incomeDtos = leaseUserOwnedProductMapper.getHourIncomeList(leaseUserOwnedProducts,coin, start, end);
Map<String, LeaseUserOwnedProduct> collect = leaseUserOwnedProducts.stream()
.collect(Collectors.toMap(item-> item.getUser() + "-" + item.getMiner()+ "-" + item.getCoin(),Function.identity()));
for (HourIncomeDto hourIncomeDto : incomeDtos) {
String key = hourIncomeDto.getUser() + "-" + hourIncomeDto.getMiner()+ "-" + coin;
LeaseUserOwnedProduct leaseUserOwnedProduct = collect.get(key) ;
leaseUserOwnedProduct.setSettleIncome(hourIncomeDto.getIncome().add(leaseUserOwnedProduct.getSettleIncome()));
//leaseUserOwnedProduct.setSettleUsdtIncome(hourIncomeDto.getUsdtIncome().add(leaseUserOwnedProduct.getSettleUsdtIncome()));
updateList.add(leaseUserOwnedProduct);
}
}
return updateList;
}
///**
// * 计算已购生效机器过去一小时收益
// * @param coin
// */
//public List<LeaseUserOwnedProduct> computeIncome(String coin){
// //获取当前时间整点时间
// LocalDateTime now = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0);
// //获取当天开始时间
// LocalDateTime startOfDay = now.with(LocalTime.MIN);
// LocalDateTime end = now.minusHours(1);
// LocalDateTime start = now.minusHours(2);
// //1. 查询在有效期内的已购机器
// LambdaQueryWrapper<LeaseUserOwnedProduct> wrapper = new LambdaQueryWrapper<LeaseUserOwnedProduct>()
// .eq(LeaseUserOwnedProduct::getCoin, coin)
// .eq(LeaseUserOwnedProduct::getStatus, 0);
// List<LeaseUserOwnedProduct> leaseUserOwnedProducts = leaseUserOwnedProductMapper.selectList(wrapper);
// System.out.println("个人收益--矿机: " + JSONUtil.toJsonPrettyStr(leaseUserOwnedProducts));
// //2.获取近一个小时矿机的收益 + 并计算实时收益
// List<LeaseUserOwnedProduct> updateList = new ArrayList<>();
// if (!leaseUserOwnedProducts.isEmpty()){
// Map<String, LeaseUserOwnedProduct> collect = new HashMap<>();
// Set<Long> orderInfoIds = new HashSet<>();
// for (LeaseUserOwnedProduct item : leaseUserOwnedProducts) {
// collect.put(item.getUser() + "-" + item.getMiner() + "-" + item.getCoin(), item);
// orderInfoIds.add(item.getOrderId());
// }
//
// //2.1 查询当天已支付订单
// //查询订单详情对应的信息formAddress + fromChain + fromSymbol + toAddress + toChain + toSymbol
// List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.getOrderItemByOrderIds(orderInfoIds);
// Map<String, LeaseOrderItem> collect1 = leaseOrderItems.stream().collect(Collectors.toMap(item -> item.getUser() + "-" + item.getMiner() + "-" + item.getCoin(), Function.identity()));
//
// List<HourIncomeDto> incomeDtos = leaseUserOwnedProductMapper.getHourIncomeList(leaseUserOwnedProducts,coin, start, end);
// for (HourIncomeDto hourIncomeDto : incomeDtos) {
// String key = hourIncomeDto.getUser() + "-" + hourIncomeDto.getMiner()+ "-" + coin;
// System.out.println("个人收益--矿机详情: " + key);
// LeaseUserOwnedProduct leaseUserOwnedProduct = collect.get(key) ;
// LeaseOrderItem leaseOrderItem = collect1.get(key);
// System.out.println("个人收益--订单详情: " + JSONUtil.toJsonPrettyStr(leaseOrderItem));
// if (leaseOrderItem != null && leaseOrderItem.getStatus() == 1){
// BigDecimal coinIncome = hourIncomeDto.getIncome().add(leaseUserOwnedProduct.getCurrentIncome());
// BigDecimal usdtIncome = hourIncomeDto.getUsdtIncome().add(leaseUserOwnedProduct.getCurrentUsdtIncome());
// //当日待结算收益不为0把待结算收益加到当前收益中
// if (leaseUserOwnedProduct.getSettleIncome().compareTo(BigDecimal.ZERO) > 0){
// coinIncome = coinIncome.add(leaseUserOwnedProduct.getSettleIncome());
// usdtIncome = usdtIncome.add(leaseUserOwnedProduct.getSettleUsdtIncome());
// leaseUserOwnedProduct.setSettleIncome(BigDecimal.ZERO);
// leaseUserOwnedProduct.setSettleUsdtIncome(BigDecimal.ZERO);
// }
// leaseUserOwnedProduct.setCurrentIncome(coinIncome);
// leaseUserOwnedProduct.setCurrentUsdtIncome(usdtIncome);
//
// }else{
// leaseUserOwnedProduct.setSettleIncome(hourIncomeDto.getIncome().add(leaseUserOwnedProduct.getSettleIncome()));
// leaseUserOwnedProduct.setSettleUsdtIncome(hourIncomeDto.getUsdtIncome().add(leaseUserOwnedProduct.getSettleUsdtIncome()));
// }
// if (now.equals(startOfDay)){
// leaseUserOwnedProduct.setSettleIncome(BigDecimal.ZERO);
// leaseUserOwnedProduct.setSettleUsdtIncome(BigDecimal.ZERO) ;
// }
//
// updateList.add(leaseUserOwnedProduct);
// }
// }
// return updateList;
//}
/**
* 批量修改已购机器的收益
* @param updateList
*/
public void batchUpdateLeaseUserOwnedProducts(List<LeaseUserOwnedProduct> updateList) {
// 用于记录执行过程中的异常
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < updateList.size(); i += BATCH_SIZE) {
int toIndex = Math.min(i + BATCH_SIZE, updateList.size());
List<LeaseUserOwnedProduct> subList = updateList.subList(i, toIndex);
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
if (!subList.isEmpty()){
leaseUserOwnedProductMapper.updateBatchIncome(subList);
}
} catch (Exception e) {
exceptionRef.set(e);
throw new RuntimeException(e);
}
}, executorService);
futures.add(future);
}
// 等待所有任务完成
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
try {
allFutures.get();
} catch (InterruptedException | ExecutionException e) {
// 如果有异常,将异常信息设置到 exceptionRef 中
exceptionRef.set(e);
}
// 如果有异常,抛出异常触发事务回滚
if (exceptionRef.get() != null) {
throw new RuntimeException("批量更新数据时发生错误", exceptionRef.get());
}
}
}

View File

@@ -0,0 +1,116 @@
package com.m2pool.lease.task;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.m2pool.lease.dto.ProductMachineDto;
import com.m2pool.lease.entity.LeaseProductMachine;
import com.m2pool.lease.mapper.LeaseProductMachineMapper;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicReference;
/**
* @Description 矿机实时算力入库
* @Date 2025/11/7 14:16
* @Author yyb
*/
@Configuration
@EnableScheduling
public class RealPowerInsetTask {
@Resource
private LeaseProductMachineMapper leaseProductMachineMapper;
private static final int BATCH_SIZE = 1000;
private static final int THREAD_POOL_SIZE = Runtime.getRuntime().availableProcessors();
private final ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
public void batchInsert(String coin,List<ProductMachineDto> recentlyFiveMinutesData) {
// 用于记录执行过程中的异常
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < recentlyFiveMinutesData.size(); i += BATCH_SIZE) {
int toIndex = Math.min(i + BATCH_SIZE, recentlyFiveMinutesData.size());
List<ProductMachineDto> subList = recentlyFiveMinutesData.subList(i, toIndex);
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
leaseProductMachineMapper.batchInsertPowers(coin, subList);
} catch (Exception e) {
exceptionRef.set(e);
throw new RuntimeException(e);
}
}, executorService);
futures.add(future);
}
// 等待所有任务完成
CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
try {
allFutures.get();
} catch (InterruptedException | ExecutionException e) {
// 如果有异常,将异常信息设置到 exceptionRef 中
exceptionRef.set(e);
}
// 如果有异常,抛出异常触发事务回滚
if (exceptionRef.get() != null) {
System.out.println("批量插入数据实时算力数据出错"+exceptionRef.get());
throw new RuntimeException("批量插入数据实时算力数据出错", exceptionRef.get());
}
}
public List<ProductMachineDto> getRealPower(String coin){
List<LeaseProductMachine> leaseProductMachines = leaseProductMachineMapper.selectList(new LambdaQueryWrapper<LeaseProductMachine>()
.eq(LeaseProductMachine::getDel, false));
List<ProductMachineDto> recentlyFiveMinutesData = leaseProductMachineMapper.getRecentlyFiveMinutesData(leaseProductMachines, coin);
for (ProductMachineDto recentlyFiveMinutesDatum : recentlyFiveMinutesData) {
recentlyFiveMinutesDatum.setComputingPower(recentlyFiveMinutesDatum.getComputingPower()
.divide(BigDecimal.valueOf(24 * 60 * 60),2, RoundingMode.HALF_UP));
}
return recentlyFiveMinutesData;
}
@Scheduled(cron = "0 0/5 * * * ? ")
@DSTransactional
public void nexaRealPowerInset(){
List<ProductMachineDto> nexaPower = getRealPower("nexa");
batchInsert("nexa",nexaPower);
}
@Scheduled(cron = "0 0/5 * * * ? ")
@DSTransactional
public void monaRealPowerInset(){
List<ProductMachineDto> monaPower = getRealPower("mona");
batchInsert("mona",monaPower);
}
@Scheduled(cron = "0 0/5 * * * ? ")
@DSTransactional
public void rxdRealPowerInset(){
List<ProductMachineDto> rxdPower = getRealPower("mona");
batchInsert("rxd",rxdPower);
}
@Scheduled(cron = "0 0/5 * * * ? ")
@DSTransactional
public void grsRealPowerInset(){
List<ProductMachineDto> rxdPower = getRealPower("grs");
batchInsert("grs",rxdPower);
}
}

View File

@@ -0,0 +1,46 @@
package com.m2pool.lease.task.info;
import lombok.Data;
import java.math.BigDecimal;
/**
* @Description 算法信息类
* @Date 2025/12/16 15:43
* @Author yyb
*/
@Data
public class AlgorithmInfo {
/**
* 币种名称
*/
private String coin;
/**
* 算法名称
*/
private String name;
/**
* 挖矿算力
*/
private BigDecimal hashrate;
/**
* 功耗
*/
private BigDecimal power;
/**
* 报块间隔
*/
private BigDecimal blockInterval;
/**
* 报块奖励
*/
private BigDecimal blockReward;
private BigDecimal price;
}

View File

@@ -0,0 +1,34 @@
package com.m2pool.lease.task.info;
import lombok.Data;
import java.math.BigDecimal;
/**
* @Description 算法信息类
* @Date 2025/12/16 15:43
* @Author yyb
*/
@Data
public class BlockInfo {
/**
* 币种
*/
private String coin;
/**
* 每日报块数
*/
private String blocks;
/**
* 报块间隔
*/
private BigDecimal blockInterval;
/**
* 报块奖励
*/
private BigDecimal blockReward;
}

View File

@@ -0,0 +1,34 @@
package com.m2pool.lease.task.info;
import lombok.Data;
import java.util.List;
/**
* @Description gpu 信息类
* @Date 2025/12/16 15:42
* @Author yyb
*/
@Data
public class GpuInfo {
/**
* gpu id
*/
private Long id;
/**
* gpu 名称
*/
private String name;
/**
* gpu 发布日期
*/
private String release_date;
/**
* gpu 算法信息
*/
private List<AlgorithmInfo> algorithms;
}

View File

@@ -0,0 +1,21 @@
package com.m2pool.lease.task.info;
import lombok.Data;
@Data
public class MiningRewardInfo {
private int id;
/**
* 币种名
*/
private String tag;
private String name;
private String estimated_rewards;
private String estimated_rewards24;
private String btc_revenue;
private String btc_revenue24;
private double revenue;
private double revenue24;
private double profit;
private double profit24;
}

View File

@@ -0,0 +1,31 @@
package com.m2pool.lease.task.info;
import lombok.Builder;
import lombok.Data;
import java.math.BigDecimal;
/**
* @Description 月收益信息
* @Date 2025/12/16 15:43
* @Author yyb
*/
@Builder
@Data
public class MonthIncomeInfo {
/**
* 算法名称
*/
private String algorithm;
/**
* 功耗
*/
private BigDecimal power;
/**
* 矿机算力 单位H/S
*/
private BigDecimal hashrate;
}