update 矿机离线邮箱发送定时任务修改
This commit is contained in:
@@ -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;
|
||||||
|
}
|
||||||
@@ -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";
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
@@ -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 门罗收益
|
||||||
|
|
||||||
|
}
|
||||||
@@ -101,9 +101,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.NEXA.getCoin()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.NEXA.getCoin()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -190,9 +190,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.NEXA.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.NEXA.getName()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -277,9 +277,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.MONA.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.MONA.getName()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -363,9 +363,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.DGBO.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.DGBO.getName()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -449,9 +449,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.DGBQ.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.DGBQ.getName()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -535,9 +535,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.DGBS.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.DGBS.getName()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -621,9 +621,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.RXD.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.RXD.getName()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -707,9 +707,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.ALPH.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.ALPH.getName()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -793,9 +793,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.ENX.getName()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.ENX.getName()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -882,9 +882,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.MONERO.getCoin()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.MONERO.getCoin()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
@@ -973,9 +973,9 @@ public class OffLineNoticeTask {
|
|||||||
//执行通知
|
//执行通知
|
||||||
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
List<String> emails = userEmails.getOrDefault(e.getUser(), null);
|
||||||
if(StringUtils.isNotNull(emails)){
|
if(StringUtils.isNotNull(emails)){
|
||||||
String text = "您的"+Pools.SHA3X.getCoin()+"下挖矿账户: "+e.getUser()+"有矿机离线!离线矿机列表如下:\n" +
|
String text = "您的"+Pools.SHA3X.getCoin()+"下挖矿账户: "+e.getUser()+"\n有" +
|
||||||
e.getMiners() + " \n"+
|
e.getOffline() + "台矿机离线!\n"+
|
||||||
"若您的矿机是因异常断开,请及时处理!";
|
"若您的矿机是因异常断开,请及时处理!";
|
||||||
emails.stream().forEach(email ->{
|
emails.stream().forEach(email ->{
|
||||||
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
System.out.println("用户"+e.getUser()+"矿机离线通知到"+email);
|
||||||
EmailEntity entity = new EmailEntity();
|
EmailEntity entity = new EmailEntity();
|
||||||
|
|||||||
@@ -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信息入库成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user