update 矿机离线邮箱发送定时任务修改

This commit is contained in:
yyb
2025-10-13 13:49:23 +08:00
parent 6ed6c2fc70
commit db21058db1
10 changed files with 686 additions and 33 deletions

View File

@@ -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;
}

View File

@@ -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";
}

View File

@@ -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<MinerIncomeDto> 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<HourIncome> list);
}

View File

@@ -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<HourIncome> hourIncomes) {
// 用于记录执行过程中的异常
AtomicReference<Exception> exceptionRef = new AtomicReference<>();
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (int i = 0; i < hourIncomes.size(); i += BATCH_SIZE) {
int toIndex = Math.min(i + BATCH_SIZE, hourIncomes.size());
List<HourIncome> subList = hourIncomes.subList(i, toIndex);
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
incomeMapper.batchInsertHourIncomes(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());
}
}
@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<MinerIncomeDto> 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<HourIncome> 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<MinerIncomeDto> 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<HourIncome> 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<MinerIncomeDto> 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<HourIncome> 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<MinerIncomeDto> 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<HourIncome> 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 门罗收益
}

View File

@@ -101,9 +101,9 @@ public class OffLineNoticeTask {
//执行通知
List<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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<String> 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();

View File

@@ -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信息入库成功");
}
}
}

View File

@@ -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;
}

View File

@@ -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<XtmPoolInfo> xtmPoolInfoList = gson.fromJson(jsonData, new TypeToken<List<XtmPoolInfo>>() {}.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;
}
}

View File

@@ -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;
}

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.m2pool.pool.mapper.IncomeMapper">
<select id="getMinerAvgPower" resultType="com.m2pool.pool.dto.MinerIncomeDto">
select `user`,miner,avg(mhs30m) as avgPower from ${coin}_mhsv2
where `date` >= #{start} and `date` <![CDATA[ <= ]]> #{end}
group by `user`,miner
</select>
<select id="getVaildBlcoks" resultType="java.math.BigDecimal">
select count(*) from ${coin}_blkreportprofitv2 where state = 1 and `date` >= #{start} and `date` <![CDATA[ <= ]]> #{end}
</select>
<insert id="batchInsertHourIncomes">
INSERT INTO ${coin}_hour_income (user, miner, income, usdt_income)
VALUES
<foreach collection="list" item="item" separator=",">
(#{item.user}, #{item.miner}, #{item.income}, #{item.usdtIncome})
</foreach>
</insert>
</mapper>