From db21058db109c9eee7af9eac4227f7c5d7679ed6 Mon Sep 17 00:00:00 2001 From: yyb <1416014977@qq.com> Date: Mon, 13 Oct 2025 13:49:23 +0800 Subject: [PATCH] =?UTF-8?q?update=20=E7=9F=BF=E6=9C=BA=E7=A6=BB=E7=BA=BF?= =?UTF-8?q?=E9=82=AE=E7=AE=B1=E5=8F=91=E9=80=81=E5=AE=9A=E6=97=B6=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/m2pool/pool/entity/HourIncome.java | 46 ++++ .../java/com/m2pool/pool/enums/RedisKey.java | 25 ++ .../com/m2pool/pool/mapper/IncomeMapper.java | 45 ++++ .../java/com/m2pool/pool/task/IncomeTask.java | 253 ++++++++++++++++++ .../m2pool/pool/task/OffLineNoticeTask.java | 66 ++--- .../m2pool/pool/task/XtmBlockInfoTask.java | 35 +++ .../com/m2pool/pool/utils/XtmPoolInfo.java | 47 ++++ .../java/com/m2pool/pool/utils/dome4j.java | 159 +++++++++++ .../com/m2pool/pool/vo/DataSupplementVo.java | 16 ++ .../resources/mapper/pool/IncomeMapper.xml | 27 ++ 10 files changed, 686 insertions(+), 33 deletions(-) create mode 100644 m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/entity/HourIncome.java create mode 100644 m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/enums/RedisKey.java create mode 100644 m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/mapper/IncomeMapper.java create mode 100644 m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/IncomeTask.java create mode 100644 m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/XtmBlockInfoTask.java create mode 100644 m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/utils/XtmPoolInfo.java create mode 100644 m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/utils/dome4j.java create mode 100644 m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/vo/DataSupplementVo.java create mode 100644 m2pool-modules/m2pool-pool/src/main/resources/mapper/pool/IncomeMapper.xml diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/entity/HourIncome.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/entity/HourIncome.java new file mode 100644 index 0000000..aad3d52 --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/entity/HourIncome.java @@ -0,0 +1,46 @@ +package com.m2pool.pool.entity; + + +import lombok.Builder; +import lombok.Data; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.time.LocalDateTime; + +/** + * @Description 币种实时收益实体类 + * @Date 2024/6/14 15:57 + * @Author dy + */ +@Data +@Builder +public class HourIncome implements Serializable { + + private static final long serialVersionUID=1L; + + + private Long id; + + /** + * 挖矿账户 + */ + private String user; + + /** + * 矿工编号 + */ + private String miner; + + /** + * 挖矿收益nexa 币 + */ + private BigDecimal income; + + /** + * 挖矿收益 稳定币usdt + */ + private BigDecimal usdtIncome; + + private LocalDateTime createTime; +} diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/enums/RedisKey.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/enums/RedisKey.java new file mode 100644 index 0000000..2b635b0 --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/enums/RedisKey.java @@ -0,0 +1,25 @@ +package com.m2pool.pool.enums; + +/** + * @Description redis key + * @Date 2025/8/18 09:49 + * @Author yyb + */ +public class RedisKey { + /** + * nexa币种实时价格 + */ + public static final String NEXA_PRICE = "nexa:price"; + /** + * grs币种实时价格 + */ + public static final String MONA_PRICE = "mona:price"; + /** + * rxd币种实时价格 + */ + public static final String RXD_PRICE = "rxd:price"; + /** + * grs币种实时价格 + */ + public static final String GRS_PRICE = "grs:price"; +} diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/mapper/IncomeMapper.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/mapper/IncomeMapper.java new file mode 100644 index 0000000..70679cd --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/mapper/IncomeMapper.java @@ -0,0 +1,45 @@ +package com.m2pool.pool.mapper; + +import com.m2pool.common.datasource.annotation.DistributionDB; +import com.m2pool.common.datasource.annotation.HashRateDB; +import com.m2pool.pool.dto.MinerIncomeDto; +import com.m2pool.pool.entity.HourIncome; +import org.apache.ibatis.annotations.Param; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.List; + +/** + * @Description 矿机收益 + * @Date 2025/8/15 17:47 + * @Author yyb + */ +public interface IncomeMapper { + /** + * 获取矿机平均算力 + * @param coin + * @param start + * @param end + * @return + */ + @HashRateDB + List getMinerAvgPower(@Param("coin")String coin,@Param("start")LocalDateTime start, @Param("end")LocalDateTime end); + + /** + * 获取有效块数 + * @param coin + * @param start + * @param end + * @return + */ + @DistributionDB + BigDecimal getVaildBlcoks(@Param("coin")String coin, @Param("start")LocalDateTime start, @Param("end")LocalDateTime end); + + /** + * 批量插入小时收益 + * @param list + * @return + */ + int batchInsertHourIncomes(@Param("coin")String coin,@Param("list")List list); +} diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/IncomeTask.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/IncomeTask.java new file mode 100644 index 0000000..a488000 --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/IncomeTask.java @@ -0,0 +1,253 @@ +package com.m2pool.pool.task; + +import com.m2pool.common.redis.service.RedisService; +import com.m2pool.pool.dto.MinerIncomeDto; +import com.m2pool.pool.entity.HourIncome; +import com.m2pool.pool.enums.RedisKey; +import com.m2pool.pool.mapper.IncomeMapper; +import com.m2pool.pool.mapper.PoolMapper; +import org.apache.ibatis.session.SqlSession; +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.time.LocalDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; +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.stream.Collectors; +/** + * @Description 矿机收益 定时任务 + * @Date 2025/8/15 17:12 + * @Author yyb + */ +@Configuration +@EnableScheduling +public class IncomeTask { + + + @Resource + private IncomeMapper incomeMapper; + + + @Resource + private RedisService redisService; + + @Resource + private PoolMapper poolMapper; + + 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 batchInsertHourIncomes(String coin, List hourIncomes) { + // 用于记录执行过程中的异常 + AtomicReference exceptionRef = new AtomicReference<>(); + List> futures = new ArrayList<>(); + + for (int i = 0; i < hourIncomes.size(); i += BATCH_SIZE) { + int toIndex = Math.min(i + BATCH_SIZE, hourIncomes.size()); + List subList = hourIncomes.subList(i, toIndex); + + CompletableFuture future = CompletableFuture.runAsync(() -> { + try { + incomeMapper.batchInsertHourIncomes(coin, subList); + } catch (Exception e) { + exceptionRef.set(e); + throw new RuntimeException(e); + } + }, executorService); + + futures.add(future); + } + // 等待所有任务完成 + CompletableFuture 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()); + } + } + + @Scheduled(cron = "5 21 0/1 * * ? ") + public void nexaIncomeTask() { + LocalDateTime now = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0); + LocalDateTime end = now.minusHours(1); + LocalDateTime start = now.minusHours(2); + System.out.println("nexa 矿机收益入库开始"+ LocalDateTime.now()); + //1.获取m2pool中 1-2小时前的单个矿机算力 + List nexaMinerIncomes = incomeMapper.getMinerAvgPower("nexa", start, end); + //2.获取矿池nexa 总算力 + BigDecimal totalPower = nexaMinerIncomes.stream() + .map(MinerIncomeDto::getAvgPower) + .reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + //3.获取当前nexa币价 + String price = redisService.getCacheObject(RedisKey.NEXA_PRICE); + BigDecimal nexaPrice; + if (price == null){ + nexaPrice = poolMapper.selectPrice("nexa"); + }else{ + nexaPrice = new BigDecimal(price); + } + //4.获取nexa 1-2小时前的报块数 + BigDecimal nexaBlocks = incomeMapper.getVaildBlcoks("nexa", start, end); + + //5.计算单个矿机的收益 + List totalIncomes = new ArrayList<>(); + nexaMinerIncomes.forEach(minerIncomeDto -> { + BigDecimal income = nexaBlocks.multiply(minerIncomeDto.getAvgPower().divide(totalPower, 8, RoundingMode.HALF_UP)); + BigDecimal usdtIncome = income.multiply(nexaPrice); + totalIncomes.add(HourIncome.builder() + .user(minerIncomeDto.getUser()) + .miner(minerIncomeDto.getMiner()) + .income(income) + .usdtIncome(usdtIncome) + .build()); + }); + //6.矿机收益入库 + batchInsertHourIncomes("nexa",totalIncomes); + + System.out.println("nexa 矿机收益入库完成"+ LocalDateTime.now()); + } + @Scheduled(cron = "15 22 0/1 * * ? ") + public void rxdIncomeTask() { + LocalDateTime now = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0); + LocalDateTime end = now.minusHours(1); + LocalDateTime start = now.minusHours(2); + System.out.println("rxd 矿机收益入库开始"+ LocalDateTime.now()); + //1.获取m2pool中 1-2小时前的单个矿机算力 + List rxdMinerIncomes = incomeMapper.getMinerAvgPower("rxd", start, end); + //2.获取矿池rxd总算力 + BigDecimal totalPower = rxdMinerIncomes.stream() + .map(MinerIncomeDto::getAvgPower) + .reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + //3.获取当前rxd币价 + String price = redisService.getCacheObject(RedisKey.RXD_PRICE); + BigDecimal rxdPrice; + if (price == null){ + rxdPrice = poolMapper.selectPrice("rxd"); + }else{ + rxdPrice = new BigDecimal(price); + } + //4.获取rxd 1-2小时前的报块数 + BigDecimal rxdBlocks = incomeMapper.getVaildBlcoks("rxd", start, end); + + //5.计算单个矿机的收益 + List totalIncomes = new ArrayList<>(); + rxdMinerIncomes.forEach(minerIncomeDto -> { + BigDecimal income = rxdBlocks.multiply(minerIncomeDto.getAvgPower().divide(totalPower, 8, RoundingMode.HALF_UP)); + BigDecimal usdtIncome = income.multiply(rxdPrice); + totalIncomes.add(HourIncome.builder() + .user(minerIncomeDto.getUser()) + .miner(minerIncomeDto.getMiner()) + .income(income) + .usdtIncome(usdtIncome) + .build()); + }); + //6.矿机收益入库 + batchInsertHourIncomes("rxd",totalIncomes); + + System.out.println("rxd 矿机收益入库完成"+ LocalDateTime.now()); + } + @Scheduled(cron = "25 23 0/1 * * ? ") + public void monaIncomeTask() { + LocalDateTime now = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0); + LocalDateTime end = now.minusHours(1); + LocalDateTime start = now.minusHours(2); + System.out.println("mona 矿机收益入库开始"+ LocalDateTime.now()); + //1.获取m2pool中 1-2小时前的单个矿机算力 + List monaMinerIncomes = incomeMapper.getMinerAvgPower("mona", start, end); + //2.获取矿池mona总算力 + BigDecimal totalPower = monaMinerIncomes.stream() + .map(MinerIncomeDto::getAvgPower) + .reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + //3.获取当前mona币价 + String price = redisService.getCacheObject(RedisKey.MONA_PRICE); + BigDecimal monaPrice; + if (price == null){ + monaPrice = poolMapper.selectPrice("mona"); + }else{ + monaPrice = new BigDecimal(price); + } + //4.获取mona 1-2小时前的报块数 + BigDecimal monaBlocks = incomeMapper.getVaildBlcoks("rxd", start, end); + + //5.计算单个矿机的收益 + List totalIncomes = new ArrayList<>(); + monaMinerIncomes.forEach(minerIncomeDto -> { + BigDecimal income = monaBlocks.multiply(minerIncomeDto.getAvgPower().divide(totalPower, 8, RoundingMode.HALF_UP)); + BigDecimal usdtIncome = income.multiply(monaPrice); + totalIncomes.add(HourIncome.builder() + .user(minerIncomeDto.getUser()) + .miner(minerIncomeDto.getMiner()) + .income(income) + .usdtIncome(usdtIncome) + .build()); + }); + //6.矿机收益入库 + batchInsertHourIncomes("mona",totalIncomes); + + System.out.println("mona 矿机收益入库完成"+ LocalDateTime.now()); + } + @Scheduled(cron = "35 24 0/1 * * ? ") + public void grsIncomeTask() { + LocalDateTime now = LocalDateTime.now().withMinute(0).withSecond(0).withNano(0); + LocalDateTime end = now.minusHours(1); + LocalDateTime start = now.minusHours(2); + System.out.println("grs 矿机收益入库开始"+ LocalDateTime.now()); + //1.获取m2pool中 1-2小时前的单个矿机算力 + List grsMinerIncomes = incomeMapper.getMinerAvgPower("rxd", start, end); + //2.获取矿池grs总算力 + BigDecimal totalPower = grsMinerIncomes.stream() + .map(MinerIncomeDto::getAvgPower) + .reduce(BigDecimal::add).orElse(BigDecimal.ZERO); + //3.获取当前grs币价 + String price = redisService.getCacheObject(RedisKey.GRS_PRICE); + BigDecimal grsPrice ; + if (price == null){ + grsPrice = poolMapper.selectPrice("grs"); + }else{ + grsPrice = new BigDecimal(price); + } + //4.获取rxd 1-2小时前的报块数 + BigDecimal grsBlocks = incomeMapper.getVaildBlcoks("grs", start, end); + + //5.计算单个矿机的收益 + List totalIncomes = new ArrayList<>(); + grsMinerIncomes.forEach(minerIncomeDto -> { + BigDecimal income = grsBlocks.multiply(minerIncomeDto.getAvgPower().divide(totalPower, 8, RoundingMode.HALF_UP)); + BigDecimal usdtIncome = income.multiply(grsPrice); + totalIncomes.add(HourIncome.builder() + .user(minerIncomeDto.getUser()) + .miner(minerIncomeDto.getMiner()) + .income(income) + .usdtIncome(usdtIncome) + .build()); + }); + //6.矿机收益入库 + batchInsertHourIncomes("grs",totalIncomes); + + System.out.println("grs 矿机收益入库完成"+ LocalDateTime.now()); + } + + //TODO 门罗收益 + +} diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/OffLineNoticeTask.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/OffLineNoticeTask.java index 1c683e5..f7f9bcf 100644 --- a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/OffLineNoticeTask.java +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/OffLineNoticeTask.java @@ -101,9 +101,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.NEXA.getCoin()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.NEXA.getCoin()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -190,9 +190,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.NEXA.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.NEXA.getName()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -277,9 +277,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.MONA.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.MONA.getName()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -363,9 +363,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.DGBO.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.DGBO.getName()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -449,9 +449,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.DGBQ.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.DGBQ.getName()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -535,9 +535,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.DGBS.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.DGBS.getName()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -621,9 +621,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.RXD.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.RXD.getName()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -707,9 +707,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.ALPH.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.ALPH.getName()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -793,9 +793,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.ENX.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.ENX.getName()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -882,9 +882,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.MONERO.getCoin()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.MONERO.getCoin()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); @@ -973,9 +973,9 @@ public class OffLineNoticeTask { //执行通知 List emails = userEmails.getOrDefault(e.getUser(), null); if(StringUtils.isNotNull(emails)){ - String text = "您的"+Pools.SHA3X.getCoin()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" + - e.getMiners() + " \n"+ - "若您的矿机是因异常断开,请及时处理!"; + String text = "您的"+Pools.SHA3X.getCoin()+"下挖矿账户: "+e.getUser()+"\n有" + + e.getOffline() + "台矿机离线!\n"+ + "若您的矿机是因异常断开,请及时处理!"; emails.stream().forEach(email ->{ System.out.println("用户"+e.getUser()+"矿机离线通知到"+email); EmailEntity entity = new EmailEntity(); diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/XtmBlockInfoTask.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/XtmBlockInfoTask.java new file mode 100644 index 0000000..4568eea --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/task/XtmBlockInfoTask.java @@ -0,0 +1,35 @@ +package com.m2pool.pool.task; + +import com.m2pool.pool.entity.BlockInfo; +import com.m2pool.pool.mapper.PoolMapper; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; + +import javax.annotation.Resource; + +import static com.m2pool.pool.utils.dome4j.*; + +/** + * @Description TODO + * @Date 2025/9/28 09:39 + * @Author yyb + */ +@Configuration +@EnableScheduling +public class XtmBlockInfoTask { + + @Resource + private PoolMapper poolMapper; + + @Scheduled(cron = "0 0/10 * * * ?") + public void Sha3xBlockInfoToDB(){ + BlockInfo xtmBlockInfoForXml = getSha3xBlockInfoForXml(); + //入库 + int i = poolMapper.insertXtmBlockInfo(xtmBlockInfoForXml); + if (i > 0){ + System.out.println("sha3x信息入库成功"); + } + + } +} diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/utils/XtmPoolInfo.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/utils/XtmPoolInfo.java new file mode 100644 index 0000000..eda6b4f --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/utils/XtmPoolInfo.java @@ -0,0 +1,47 @@ +package com.m2pool.pool.utils; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +public class XtmPoolInfo { + private int id; + private String name; + private String icon_class; + private int block_total; + private Object rewards; + private int isolated_block_total; + private String network_hashrate; + private String pool_hashrate; + private int miner_count; + private String coin_price; + private Object lucky_3d; + private Object lucky_7d; + private Object lucky_30d; + private int status; + private int default_fee; + private String explore_url; + private String calculator; + private int rank; + private String algorithm; + private int time; + private String tutorial_address; + private String pay_method; + private Object merge_mining; + private Object max_supply; + private Object circulating_supply; + private String address; + private String mining_address; + private int min_withdraw_amount; + private String base_reward; + private double block_time; + private String suitable_unit; + private long height; + private String created_at; + private String updated_at; + private int new_; + private String location; +} diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/utils/dome4j.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/utils/dome4j.java new file mode 100644 index 0000000..238efeb --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/utils/dome4j.java @@ -0,0 +1,159 @@ +package com.m2pool.pool.utils; + +import com.alibaba.nacos.shaded.com.google.gson.Gson; +import com.alibaba.nacos.shaded.com.google.gson.reflect.TypeToken; +import com.m2pool.pool.entity.BlockInfo; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * @Description TODO + * @Date 2025/9/28 09:24 + * @Author yyb + */ +public class dome4j { + public static void main(String[] args) throws Exception { + getSha3xBlockInfoForXml(); + } + + + public static BlockInfo getSha3xBlockInfoForXml() { + try { + // 从指定 URL 获取 XML 数据 + String xmlData = fetchXmlData("https://www.dxpool.com/api/address-mining/pools"); + // 移除提示信息 + BlockInfo blockInfo = extractXtmBlockInfo(xmlData); + System.out.println(blockInfo); + return blockInfo; + + } catch (Exception e) { + return null; + } + } + + + /** + * 从 JSON 数据中提取 id 为 30 的节点信息到 BlockInfo 中 + * @param jsonData JSON 数据字符串 + * @return BlockInfo 对象,若未找到则返回 null + */ + private static BlockInfo extractXtmBlockInfo(String jsonData) { + Gson gson = new Gson(); + List xtmPoolInfoList = gson.fromJson(jsonData, new TypeToken>() {}.getType()); + for (XtmPoolInfo xtmPoolInfo : xtmPoolInfoList) { + if (xtmPoolInfo.getId() == 30) { + BlockInfo blockInfo = new BlockInfo(); + blockInfo.setDifficulty(BigDecimal.ZERO); + blockInfo.setHeight(xtmPoolInfo.getHeight()); + blockInfo.setPrice(new BigDecimal(xtmPoolInfo.getCoin_price())); + // 转换单位为 H/s + BigDecimal powerInHPerSecond = convertToHPerSecond(xtmPoolInfo.getNetwork_hashrate()); + blockInfo.setPower(powerInHPerSecond); + + blockInfo.setReward(new BigDecimal(xtmPoolInfo.getBase_reward())); + blockInfo.setFees(new BigDecimal(xtmPoolInfo.getDefault_fee())); + blockInfo.setProfit(BigDecimal.ZERO); + return blockInfo; + } + } + return null; + } + + + + /** + * 从指定 URL 获取 XML 数据 + * @param urlStr 目标 URL + * @return XML 数据字符串 + * @throws IOException 网络请求异常 + */ + public static String fetchXmlData(String urlStr) throws IOException { + URL url = new URL(urlStr); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("GET"); + + //// 配置 HTTP 代理信息,需将代理地址和端口替换为实际值 + //String proxyHost = "127.0.0.1"; + //int proxyPort = 7897; + //Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort)); + // + //URL url = new URL(urlStr); + //// 使用代理创建连接 + //HttpURLConnection connection = (HttpURLConnection) url.openConnection(proxy); + //connection.setRequestMethod("GET"); + + try (InputStream inputStream = connection.getInputStream(); + ByteArrayOutputStream result = new ByteArrayOutputStream()) { + byte[] buffer = new byte[1024]; + int length; + while ((length = inputStream.read(buffer)) != -1) { + result.write(buffer, 0, length); + } + return result.toString(String.valueOf(StandardCharsets.UTF_8)); + } + } + + /** + * 将带单位的哈希率转换为 H/s + * @param hashrateStr 带单位的哈希率字符串,例如 "28.28 TH/s" + * @return 转换为 H/s 后的 BigDecimal 数值 + */ + private static BigDecimal convertToHPerSecond(String hashrateStr) { + // 定义正则表达式,用于匹配数值和单位 + Pattern pattern = Pattern.compile("([0-9.]+)\\s*([KMGTPEZY]?)H/s"); + Matcher matcher = pattern.matcher(hashrateStr); + + if (matcher.find()) { + BigDecimal value = new BigDecimal(matcher.group(1)); + String unit = matcher.group(2); + + // 根据单位计算换算系数 + BigInteger multiplier; + switch (unit) { + case "K": + multiplier = BigInteger.valueOf(1000); + break; + case "M": + multiplier = BigInteger.valueOf(1000000); + break; + case "G": + multiplier = BigInteger.valueOf(1000000000); + break; + case "T": + multiplier = BigInteger.valueOf(1000000000000L); + break; + case "P": + multiplier = BigInteger.valueOf(1000000000000000L); + break; + case "E": + multiplier = new BigInteger("1000000000000000000"); + break; + case "Z": + multiplier = new BigInteger("1000000000000000000000"); + break; + case "Y": + multiplier = new BigInteger("1000000000000000000000000"); + break; + default: + multiplier = BigInteger.ONE; + } + + return value.multiply(new BigDecimal(multiplier)); + } + + // 如果未匹配到有效数据,返回 0 + return BigDecimal.ZERO; + } + + +} diff --git a/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/vo/DataSupplementVo.java b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/vo/DataSupplementVo.java new file mode 100644 index 0000000..f1826ee --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/java/com/m2pool/pool/vo/DataSupplementVo.java @@ -0,0 +1,16 @@ +package com.m2pool.pool.vo; + +import lombok.Data; + +/** + * @Description + * @Date 2025/9/05 14:05 + * @Author yyb + */ +@Data +public class DataSupplementVo { + private String coin; + private String date; + // key值为 dsadasdwfddasdfsafadsfs + private String key; +} diff --git a/m2pool-modules/m2pool-pool/src/main/resources/mapper/pool/IncomeMapper.xml b/m2pool-modules/m2pool-pool/src/main/resources/mapper/pool/IncomeMapper.xml new file mode 100644 index 0000000..91fa5c6 --- /dev/null +++ b/m2pool-modules/m2pool-pool/src/main/resources/mapper/pool/IncomeMapper.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + INSERT INTO ${coin}_hour_income (user, miner, income, usdt_income) + VALUES + + (#{item.user}, #{item.miner}, #{item.income}, #{item.usdtIncome}) + + + + +