|
@@ -2,8 +2,13 @@ package com.ichaoj.ams.service.impl;
|
|
|
|
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
import cn.hutool.core.bean.BeanUtil;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
|
import cn.hutool.core.collection.CollectionUtil;
|
|
|
|
+import cn.hutool.core.collection.ListUtil;
|
|
|
|
+import cn.hutool.core.map.MapUtil;
|
|
import cn.hutool.core.thread.ThreadUtil;
|
|
import cn.hutool.core.thread.ThreadUtil;
|
|
|
|
+import cn.hutool.core.util.RandomUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
import cn.hutool.core.util.StrUtil;
|
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
|
+import com.alibaba.fastjson2.JSON;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
@@ -14,6 +19,11 @@ import com.ichaoj.ams.request.execute.CreateExecute;
|
|
import com.ichaoj.ams.request.execute.PageExecuteRequest;
|
|
import com.ichaoj.ams.request.execute.PageExecuteRequest;
|
|
import com.ichaoj.ams.request.execute.UpdateExecute;
|
|
import com.ichaoj.ams.request.execute.UpdateExecute;
|
|
import com.ichaoj.ams.response.execute.ExecuteResponse;
|
|
import com.ichaoj.ams.response.execute.ExecuteResponse;
|
|
|
|
+import com.ichaoj.ams.script.IScript;
|
|
|
|
+import com.ichaoj.ams.script.SResult;
|
|
|
|
+import com.ichaoj.ams.script.ScriptContext;
|
|
|
|
+import com.ichaoj.ams.script.model.AirdropParam;
|
|
|
|
+import com.ichaoj.ams.script.model.AirdropWallet;
|
|
import com.ichaoj.ams.service.*;
|
|
import com.ichaoj.ams.service.*;
|
|
import com.ichaoj.common.exception.ErrorServiceException;
|
|
import com.ichaoj.common.exception.ErrorServiceException;
|
|
import com.ichaoj.common.model.PublicPage;
|
|
import com.ichaoj.common.model.PublicPage;
|
|
@@ -26,9 +36,10 @@ import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import javax.annotation.Resource;
|
|
import javax.annotation.Resource;
|
|
import java.time.LocalDateTime;
|
|
import java.time.LocalDateTime;
|
|
-import java.util.HashSet;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Set;
|
|
|
|
|
|
+import java.util.*;
|
|
|
|
+import java.util.concurrent.LinkedBlockingDeque;
|
|
|
|
+import java.util.concurrent.ThreadPoolExecutor;
|
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
import java.util.stream.Collectors;
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -41,6 +52,19 @@ import java.util.stream.Collectors;
|
|
*/
|
|
*/
|
|
@Service
|
|
@Service
|
|
public class AmsExecuteRecordServiceImpl extends SuperWhaleServiceImpl<AmsExecuteRecordMapper, AmsExecuteRecord> implements IAmsExecuteRecordService {
|
|
public class AmsExecuteRecordServiceImpl extends SuperWhaleServiceImpl<AmsExecuteRecordMapper, AmsExecuteRecord> implements IAmsExecuteRecordService {
|
|
|
|
+ public static ThreadPoolExecutor taskThreadPool =
|
|
|
|
+ new ThreadPoolExecutor(2 * Runtime.getRuntime().availableProcessors(),
|
|
|
|
+ 2 * Runtime.getRuntime().availableProcessors(),
|
|
|
|
+ 10,
|
|
|
|
+ TimeUnit.SECONDS,
|
|
|
|
+ new LinkedBlockingDeque<>(500),
|
|
|
|
+ r -> {
|
|
|
|
+ Thread thread = new Thread(r);
|
|
|
|
+ thread.setName("task-thread-pool");
|
|
|
|
+ return thread;
|
|
|
|
+ }
|
|
|
|
+ );
|
|
|
|
+
|
|
@Resource
|
|
@Resource
|
|
private IAmsAirdropTaskService taskService;
|
|
private IAmsAirdropTaskService taskService;
|
|
|
|
|
|
@@ -63,7 +87,13 @@ public class AmsExecuteRecordServiceImpl extends SuperWhaleServiceImpl<AmsExecut
|
|
// .orderByDesc(AmsExecuteRecord::getCreateTime);
|
|
// .orderByDesc(AmsExecuteRecord::getCreateTime);
|
|
|
|
|
|
Page<ExecuteResponse> result = this.baseMapper.pageExecute(this.buildPageObj(executeRequest), executeRequest, SuperWhaleContext.getContext(PublicUserInfo.class).getUserId());
|
|
Page<ExecuteResponse> result = this.baseMapper.pageExecute(this.buildPageObj(executeRequest), executeRequest, SuperWhaleContext.getContext(PublicUserInfo.class).getUserId());
|
|
- return this.convertPublicPage(result, s -> BeanUtil.copyProperties(s, ExecuteResponse.class));
|
|
|
|
|
|
+ return this.convertPublicPage(result, s -> {
|
|
|
|
+ ExecuteResponse executeResponse = BeanUtil.copyProperties(s, ExecuteResponse.class);
|
|
|
|
+ if (StrUtil.isNotBlank(s.getParamsStr())) {
|
|
|
|
+ executeResponse.setAirdropParams(JSON.parseArray(s.getParamsStr(), AirdropParam.class));
|
|
|
|
+ }
|
|
|
|
+ return executeResponse;
|
|
|
|
+ });
|
|
}
|
|
}
|
|
|
|
|
|
@Override
|
|
@Override
|
|
@@ -81,25 +111,66 @@ public class AmsExecuteRecordServiceImpl extends SuperWhaleServiceImpl<AmsExecut
|
|
throw new ErrorServiceException(createExecute.getGroupName() + "为非批量号地址组,不允许交易");
|
|
throw new ErrorServiceException(createExecute.getGroupName() + "为非批量号地址组,不允许交易");
|
|
}
|
|
}
|
|
AmsAirdropProject project = verifyProject(createExecute.getProjectId());
|
|
AmsAirdropProject project = verifyProject(createExecute.getProjectId());
|
|
|
|
+
|
|
AmsAirdropTask task = verifyTask(createExecute.getTaskId(), project.getAmsProjectId());
|
|
AmsAirdropTask task = verifyTask(createExecute.getTaskId(), project.getAmsProjectId());
|
|
AmsExecuteRecord amsExecute = BeanUtil.copyProperties(createExecute, AmsExecuteRecord.class);
|
|
AmsExecuteRecord amsExecute = BeanUtil.copyProperties(createExecute, AmsExecuteRecord.class);
|
|
amsExecute.setUserId(userId);
|
|
amsExecute.setUserId(userId);
|
|
amsExecute.setCreateTime(LocalDateTime.now());
|
|
amsExecute.setCreateTime(LocalDateTime.now());
|
|
amsExecute.setTaskId(task.getAmsTaskId());
|
|
amsExecute.setTaskId(task.getAmsTaskId());
|
|
amsExecute.setProjectId(project.getAmsProjectId());
|
|
amsExecute.setProjectId(project.getAmsProjectId());
|
|
|
|
+ amsExecute.setAirdropParams(JSON.toJSONString(createExecute.getAirdropParams()));
|
|
// todo 查询是第几次执行
|
|
// todo 查询是第几次执行
|
|
this.save(amsExecute);
|
|
this.save(amsExecute);
|
|
if (StrUtil.isBlank(createExecute.getPassword())) {
|
|
if (StrUtil.isBlank(createExecute.getPassword())) {
|
|
throw new ErrorServiceException("密码不能为空!");
|
|
throw new ErrorServiceException("密码不能为空!");
|
|
}
|
|
}
|
|
- // todo 验证密码是否正确
|
|
|
|
|
|
+ List<AirdropWallet> wallets = accountService.getAirdropAddressByAccount(accountList, userId, amsExecute.getGroupName(), createExecute.getPassword());
|
|
|
|
+
|
|
|
|
+ runTask(createExecute.getIntervalMin(),
|
|
|
|
+ createExecute.getIntervalMax(),
|
|
|
|
+ amsExecute.getExecuteId(),
|
|
|
|
+ task.getTaskCode(),
|
|
|
|
+ createExecute.getAirdropParams(),
|
|
|
|
+ wallets);
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ public void runTask(long intervalMin,
|
|
|
|
+ long intervalMax,
|
|
|
|
+ String execId,
|
|
|
|
+ String taskCode,
|
|
|
|
+ List<AirdropParam> airdropParams,
|
|
|
|
+ List<AirdropWallet> wallets) {
|
|
|
|
+
|
|
|
|
+ taskThreadPool.execute(() -> {
|
|
|
|
+ Map<String, AirdropParam> airdropParamMap = new HashMap<>(airdropParams.size());
|
|
|
|
+ for (AirdropParam airdropParam : airdropParams) {
|
|
|
|
+ airdropParamMap.put(airdropParam.getName(), airdropParam);
|
|
|
|
+ }
|
|
|
|
+ for (AirdropWallet wallet : wallets) {
|
|
|
|
+ long sleepTime = RandomUtil.randomLong(intervalMin, intervalMax);
|
|
|
|
+ ThreadUtil.sleep(sleepTime, TimeUnit.MINUTES);
|
|
|
|
+ IScript script = ScriptContext.getScriptByCode(taskCode);
|
|
|
|
+ SResult sResult = script.run(airdropParamMap, wallet);
|
|
|
|
+ AmsTradeRecord tradeRecord = new AmsTradeRecord();
|
|
|
|
+ tradeRecord.setExecuteId(execId);
|
|
|
|
+ tradeRecord.setStatus(1);
|
|
|
|
+ tradeRecord.setAddress(wallet.getAddress());
|
|
|
|
+ tradeRecord.setGas(sResult.getGas());
|
|
|
|
+ tradeRecord.setTxId(sResult.getTxId());
|
|
|
|
+ tradeRecord.setCreateTime(LocalDateTime.now());
|
|
|
|
+ tradeRecord.setUpdateTime(LocalDateTime.now());
|
|
|
|
+ tradeRecord.setCurrentBalance(sResult.getCurrentBalance());
|
|
|
|
+ tradeService.save(tradeRecord);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ AmsExecuteRecord executeRecord = this.getById(execId);
|
|
|
|
+ executeRecord.setExecuteStatus(1);
|
|
|
|
+ this.updateById(executeRecord);
|
|
|
|
+ });
|
|
|
|
|
|
- ThreadUtil.execute(() -> tradeService.randomTrans(accountList
|
|
|
|
- , createExecute.getIntervalMin()
|
|
|
|
- , createExecute.getIntervalMax()
|
|
|
|
- , createExecute.getAmount()
|
|
|
|
- , createExecute.getMaxGas()
|
|
|
|
- , amsExecute.getExecuteId()));
|
|
|
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@@ -153,32 +224,52 @@ public class AmsExecuteRecordServiceImpl extends SuperWhaleServiceImpl<AmsExecut
|
|
return task;
|
|
return task;
|
|
}
|
|
}
|
|
|
|
|
|
- @Scheduled(cron = "0/59 * * * * ? ")
|
|
|
|
- public void scanExecuteStatus() {
|
|
|
|
- List<AmsExecuteRecord> list = this.list();
|
|
|
|
- for (AmsExecuteRecord executeRecord : list) {
|
|
|
|
- String executeId = executeRecord.getExecuteId();
|
|
|
|
- String userId = executeRecord.getUserId();
|
|
|
|
- String groupName = executeRecord.getGroupName();
|
|
|
|
- List<AmsAddressAccount> accounts = accountService.getByGroupNameAndUserId(groupName, userId);
|
|
|
|
- Set<String> predictSet = accounts.stream().map(AmsAddressAccount::getAddress).collect(Collectors.toSet());
|
|
|
|
- List<AmsTradeRecord> tradeRecords = tradeService.list(new LambdaQueryWrapper<AmsTradeRecord>()
|
|
|
|
- .eq(AmsTradeRecord::getExecuteId, executeId));
|
|
|
|
- Set<String> actualSet = tradeRecords.stream().map(AmsTradeRecord::getAddress).collect(Collectors.toSet());
|
|
|
|
- // 判断交易记录的地址是否
|
|
|
|
- if (CollectionUtil.containsAll(predictSet, actualSet) && CollectionUtil.containsAll(actualSet, predictSet)) {
|
|
|
|
- Set<String> confirmSet = new HashSet<>();
|
|
|
|
- for (AmsTradeRecord tradeRecord : tradeRecords) {
|
|
|
|
- if (tradeRecord.getStatus() == 1) {
|
|
|
|
- confirmSet.add(tradeRecord.getAddress());
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- // 修改状态
|
|
|
|
- if (CollectionUtil.containsAll(confirmSet, actualSet) && CollectionUtil.containsAll(actualSet, confirmSet)) {
|
|
|
|
- executeRecord.setExecuteStatus(1);
|
|
|
|
- this.updateById(executeRecord);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+// @Scheduled(cron = "0/59 * * * * ? ")
|
|
|
|
+// public void scanExecuteStatus() {
|
|
|
|
+// LambdaQueryWrapper<AmsExecuteRecord> eq = Wrappers.lambdaQuery(AmsExecuteRecord.class)
|
|
|
|
+// .eq(AmsExecuteRecord::getExecuteStatus, 0);
|
|
|
|
+// List<AmsExecuteRecord> amsExecuteRecords = this.list(eq);
|
|
|
|
+//// List<AmsExecuteRecord> list = this.list();
|
|
|
|
+// for (AmsExecuteRecord executeRecord : amsExecuteRecords) {
|
|
|
|
+// String executeId = executeRecord.getExecuteId();
|
|
|
|
+// String userId = executeRecord.getUserId();
|
|
|
|
+// String groupName = executeRecord.getGroupName();
|
|
|
|
+// List<AmsAddressAccount> accounts = accountService.getByGroupNameAndUserId(groupName, userId);
|
|
|
|
+// AmsAirdropTask task = taskService.getById(executeRecord.getTaskId());
|
|
|
|
+// String taskCode = task.getTaskCode();
|
|
|
|
+// IScript script = ScriptContext.getScriptByCode(taskCode);
|
|
|
|
+// String airdropParams = executeRecord.getAirdropParams();
|
|
|
|
+// List<AirdropParam> params = JSON.parseArray(airdropParams, AirdropParam.class);
|
|
|
|
+// Map<String, AirdropParam> paramMap = new HashMap<>();
|
|
|
|
+// for (AirdropParam param : params) {
|
|
|
|
+// paramMap.put(param.getName(), param);
|
|
|
|
+// }
|
|
|
|
+//// accounts.stream().map(account->{
|
|
|
|
+//// AirdropWallet wallet = new AirdropWallet();
|
|
|
|
+//// wallet.setAddress(account.getAddress());
|
|
|
|
+//// String keystore = account.getKeystore();
|
|
|
|
+//// accountService.getPrivateKeyByKeystore(keystore, executeId);
|
|
|
|
+//// })
|
|
|
|
+//
|
|
|
|
+//
|
|
|
|
+//// Set<String> predictSet = accounts.stream().map(AmsAddressAccount::getAddress).collect(Collectors.toSet());
|
|
|
|
+//// List<AmsTradeRecord> tradeRecords = tradeService.list(new LambdaQueryWrapper<AmsTradeRecord>()
|
|
|
|
+//// .eq(AmsTradeRecord::getExecuteId, executeId));
|
|
|
|
+//// Set<String> actualSet = tradeRecords.stream().map(AmsTradeRecord::getAddress).collect(Collectors.toSet());
|
|
|
|
+//// // 判断交易记录的地址是否
|
|
|
|
+//// if (CollectionUtil.containsAll(predictSet, actualSet) && CollectionUtil.containsAll(actualSet, predictSet)) {
|
|
|
|
+//// Set<String> confirmSet = new HashSet<>();
|
|
|
|
+//// for (AmsTradeRecord tradeRecord : tradeRecords) {
|
|
|
|
+//// if (tradeRecord.getStatus() == 1) {
|
|
|
|
+//// confirmSet.add(tradeRecord.getAddress());
|
|
|
|
+//// }
|
|
|
|
+//// }
|
|
|
|
+//// // 修改状态
|
|
|
|
+//// if (CollectionUtil.containsAll(confirmSet, actualSet) && CollectionUtil.containsAll(actualSet, confirmSet)) {
|
|
|
|
+//// executeRecord.setExecuteStatus(1);
|
|
|
|
+//// this.updateById(executeRecord);
|
|
|
|
+//// }
|
|
|
|
+//// }
|
|
|
|
+// }
|
|
|
|
+// }
|
|
}
|
|
}
|