This commit is contained in:
1186 2024-05-27 16:14:19 +08:00
commit b7d1e7b997
300 changed files with 38221 additions and 0 deletions

26
Jenkinsfile vendored Normal file
View File

@ -0,0 +1,26 @@
pipeline {
agent {
label 'test20'
}
stages {
stage('build') {
steps {
sh '''
source /etc/profile
mvn clean package -Dmaven.test.skip=true -U
'''
}
}
stage('deploy') {
steps {
sh '''
source /etc/profile
cp -f fifa-api/target/fifa-api-1.1-SNAPSHOT.jar /data/upload/fifa-maker-api/
sh /data/upload/fifa-maker-api/build.sh
'''
}
}
}
}

180
alive-api/pom.xml Normal file
View File

@ -0,0 +1,180 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alive</groupId>
<artifactId>alive-api-server</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>alive-api</artifactId>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.alive</groupId>
<artifactId>alive-db</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 阿里云 OSS SDK 依赖 -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.13.2</version>
</dependency>
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.69</version>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.15.9</version>
</dependency>
<dependency>
<groupId>com.alive</groupId>
<artifactId>alive-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>5.0.0</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>oauth.signpost</groupId>
<artifactId>signpost-core</artifactId>
<version>1.2.1.2</version>
</dependency>
<dependency>
<groupId>oauth.signpost</groupId>
<artifactId>signpost-commonshttp4</artifactId>
<version>1.2.1.2</version>
</dependency>
<dependency>
<groupId>com.twitter</groupId>
<artifactId>twitter-api-java-sdk</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
<dependency>
<groupId>org.bitcoinj</groupId>
<artifactId>bitcoinj-core</artifactId>
<version>0.15.5</version>
</dependency>
<!-- TG 依赖 -->
<dependency>
<groupId>org.telegram</groupId>
<artifactId>telegrambots</artifactId>
<version>6.0.1</version>
</dependency>
<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<exclusions>
<exclusion>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>3.1.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>
<version>1.13.1</version>
<executions>
<execution>
<goals>
<goal>addSources</goal>
<goal>addTestSources</goal>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>compileTests</goal>
<goal>removeStubs</goal>
<goal>removeTestStubs</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,18 @@
package com.alive.server;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@Slf4j
@SpringBootApplication(scanBasePackages = "com.alive")
@EnableScheduling
public class AliveApiApplication {
public static void main(String[] args) {
SpringApplication.run(AliveApiApplication.class, args);
log.info("--------------ALIVE项目启动完成-------------------");
}
}

View File

@ -0,0 +1,40 @@
package com.alive.server;
import com.alive.server.service.TelegramServer;
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
@Order(2) //通过order注解指定执行顺序
@Component
@Slf4j
public class BotRunnerInit implements CommandLineRunner {
@Autowired
private DSLContext dslContext;
@Value("${com.alive.task.bot}")
private Boolean taskBot;
@Override
public void run(String... args){
/*if(!taskBot){
return;
}
TelegramBotsApi botsApi = null;
try {
botsApi = new TelegramBotsApi(DefaultBotSession.class);
botsApi.registerBot(new TelegramServer(dslContext));
} catch (TelegramApiException e) {
log.error("TG连接网络异常-------err:{}",e.getMessage());
}*/
}
}

View File

@ -0,0 +1,32 @@
package com.alive.server;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* 实现基本的跨域请求
* @author linhongcun
*
*/
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
final CorsConfiguration corsConfiguration = new CorsConfiguration();
/*是否允许请求带有验证信息*/
corsConfiguration.setAllowCredentials(true);
/*允许访问的客户端域名*/
corsConfiguration.addAllowedOrigin("*");
/*允许服务端访问的客户端请求头*/
corsConfiguration.addAllowedHeader("*");
/*允许访问的方法名,GET POST等*/
corsConfiguration.addAllowedMethod("*");
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
return new CorsFilter(urlBasedCorsConfigurationSource);
}
}

View File

@ -0,0 +1,252 @@
package com.alive.server.api;
import com.alive.commons.util.*;
import com.alive.server.api.account.AccountSignInReq;
import com.alive.server.api.account.AccountSignInResp;
import com.alive.server.api.account.AccountSignUpReq;
import com.alive.server.api.account.InviteReq;
import com.alive.server.service.MemberService;
import com.alive.server.service.WalletService;
import com.alive.commons.annotation.Login;
import com.alive.db.entity.Vo.UserVo;
import com.alive.db.jooq.tables.pojos.TMemberPojo;
import com.alive.db.jooq.tables.records.ActivityLogRecord;
import com.alive.db.jooq.tables.records.TMemberRecord;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.sql.Timestamp;
import java.util.*;
import static com.alive.db.jooq.Tables.*;
@Slf4j
@RestController
@RequestMapping("/api/account")
@Api(tags = "账号相关")
@Transactional(isolation = Isolation.READ_COMMITTED)
@CrossOrigin(origins = "*")
public class AccountController {
@Autowired
private DSLContext dslContext;
@Autowired
private MemberService memberService;
@Autowired
private WalletService walletService;
@GetMapping("randomCode")
@ApiOperation("获取钱包签名串")
public UserVo randomCode(String account) {
Assert.isTrue(!StringUtils.isBlank(account), "Account not null");
account = account.trim().toLowerCase();
UserVo userVo = new UserVo();
String sin = NumberUtil.getUUIDBy16()+"PASSWORD";
userVo.setEncryptedString(sin);
RedisUtil.setEx(account,sin,60L);
return userVo;
}
@GetMapping("exist")
@ApiOperation("检查账号是否注册")
public Map<String, Boolean> exist(String account,Integer chainType) {
Assert.isTrue(!StringUtils.isBlank(account), "Account not null");
Assert.isTrue(chainType != null, "Chain not null");
int count = dslContext.selectCount().from(T_MEMBER)
.where(T_MEMBER.FLAG.eq((byte) 1).and(T_MEMBER.ACCOUNT.eq(account.toLowerCase().trim())))
.fetchAnyInto(Integer.class);
return Collections.singletonMap("exist", count > 0);
}
@PostMapping("signUp")
@ApiOperation("注册")
public void signUp(@RequestBody @Validated AccountSignUpReq req) {
req.setAccount(req.getAccount().trim().toLowerCase());
Assert.isTrue(RedisUtil.tryLock("AccountController.signUp." + req.getAccount(), 3), "operate too frequently");
log.info(">>> 新用户注册 - {}", JsonUtil.toJson(req));
int count = dslContext.selectCount().from(T_MEMBER)
.where(T_MEMBER.FLAG.eq((byte) 1).and(T_MEMBER.ACCOUNT.eq(req.getAccount())))
.fetchAnyInto(Integer.class);
Assert.isTrue(count == 0, "Account Exist");
if (req.getShareCode() == null || req.getShareCode().trim().isEmpty()) {
req.setShareCode("0");
}
TMemberPojo referMember = null;
if(req.getShareCode() != null && !req.getShareCode().equals("0")){
referMember = dslContext.select().from(T_MEMBER)
.where(T_MEMBER.FLAG.eq((byte) 1).and(T_MEMBER.SHARE_CODE.eq(req.getShareCode().toUpperCase())))
.fetchAnyInto(TMemberPojo.class);
Assert.notNull(referMember, "Invalid Share Code");
}
if(referMember == null){
referMember = new TMemberPojo();
referMember.setId(0);
referMember.setAllPid(",");
}
//邀请码
String shareCode = RandomStringUtils.random(6, true, true).toUpperCase(Locale.ROOT);
while (true) {
Integer tmp = dslContext.selectCount().from(T_MEMBER)
.where(T_MEMBER.SHARE_CODE.eq(shareCode))
.fetchAnyInto(Integer.class);
if (tmp == 0) {
break;
}
shareCode = RandomStringUtils.random(6, true, true).toUpperCase(Locale.ROOT);
}
//UID
String uid = "1" + RandomStringUtils.random(7, false, true).toUpperCase(Locale.ROOT);
while (true) {
Integer tmp = dslContext.selectCount().from(T_MEMBER)
.where(T_MEMBER.UID.eq(uid))
.fetchAnyInto(Integer.class);
if (tmp == 0) {
break;
}
uid = "1" + RandomStringUtils.random(7, false, true).toUpperCase(Locale.ROOT);
}
TMemberRecord memberRecord = dslContext.newRecord(T_MEMBER);
memberRecord.setAccount(req.getAccount());
memberRecord.setPasswordPay("");
memberRecord.setPasswordLogin(Md5Util.encryptPassword(req.getPublicKey()));
memberRecord.setReferId(referMember.getId());
memberRecord.setChainType(req.getChainType());
memberRecord.setUid(uid);
memberRecord.setShareCode(shareCode);
memberRecord.store();
memberRecord.setAllPid(referMember.getAllPid() + memberRecord.getId() + ",");
memberRecord.store();
walletService.initWallet(memberRecord.getId(),req.getAccount());
if(!referMember.getId().equals(0)){
//更新团队
List<Integer> allPids = memberService.splitAllPid(memberRecord.getAllPid());
dslContext.update(T_MEMBER)
.set(T_MEMBER.TEAM_NUM, T_MEMBER.TEAM_NUM.add(1))
.where(T_MEMBER.ID.in(allPids)).execute();
dslContext.update(T_MEMBER)
.set(T_MEMBER.SHARE_NUM, T_MEMBER.SHARE_NUM.add(1))
.where(T_MEMBER.ID.eq(referMember.getId())).execute();
}else{
dslContext.update(T_MEMBER)
.set(T_MEMBER.TEAM_NUM, T_MEMBER.TEAM_NUM.add(1))
.where(T_MEMBER.ID.in(memberRecord.getId())).execute();
}
}
@PostMapping("signIn")
@ApiOperation("登录")
public AccountSignInResp signIn(@RequestBody @Validated AccountSignInReq req) {
req.setAccount(req.getAccount().trim().toLowerCase());
TMemberRecord memberRecord = dslContext.selectFrom(T_MEMBER)
.where(T_MEMBER.FLAG.eq((byte) 1)
.and(T_MEMBER.ACCOUNT.eq(req.getAccount()))).fetchAny();
////todo 提示语国际化
Assert.notNull(memberRecord, "Account Not Exist");
String code = RedisUtil.get(req.getAccount());
Assert.notNull(code, "signature error");
Assert.isTrue(req.getAccount() == null || EcRecoverUtil.checkEcRecover(code, req.getPassword(), req.getAccount()), "Bad Signature");
String redisKey = "iNode:loginToken:" + memberRecord.getId();
String token = RedisUtil.get(redisKey);
if (token == null) {
token = JwtUtil.createJwtToken(memberRecord.getId().toString(), req.getAccount(), 86400L * 730L);
//30s 内的重复登录返回同一个token
RedisUtil.setEx(redisKey, token, 30);
}
//校验一下是否有统计表
walletService.verifyActivityStatisticsRecord(memberRecord.getAccount());
AccountSignInResp resp = new AccountSignInResp();
resp.setToken(token);
return resp;
}
@Login
@PostMapping("bindingRelationship")
@ApiOperation("绑定邀请关系")
public Map<String,Boolean> bindingRelationship(@RequestBody @Validated InviteReq req){
Map<String,Boolean> map = new HashMap<>();
Integer memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
//邀请人
TMemberPojo referMember = dslContext.select().from(T_MEMBER)
.where(T_MEMBER.FLAG.eq((byte) 1).and(T_MEMBER.SHARE_CODE.eq(req.getShareCode().toUpperCase())))
.fetchAnyInto(TMemberPojo.class);
Assert.notNull(referMember, "Invalid Share Code");
TMemberRecord tMemberRecord = memberService.fetchOne(memberId);
Assert.isTrue(tMemberRecord.getReferId().equals(0), "Non repeatable binding");
Assert.isTrue(!memberId.equals(referMember.getId()), "You can't invite yourself");
tMemberRecord.setReferId(referMember.getId());
tMemberRecord.setAllPid(referMember.getAllPid() + memberId + ",");
tMemberRecord.store();
//查出我的全部下级人数包含自己
Integer countNumber = memberService.findTMemberRecordCount(memberId);
//更新团队
List<Integer> allPids = memberService.splitAllPid(referMember.getAllPid());
dslContext.update(T_MEMBER)
.set(T_MEMBER.TEAM_NUM, T_MEMBER.TEAM_NUM.add(countNumber))
.where(T_MEMBER.ID.in(allPids)).execute();
dslContext.update(T_MEMBER)
.set(T_MEMBER.SHARE_NUM, T_MEMBER.SHARE_NUM.add(1))
.where(T_MEMBER.ID.eq(referMember.getId())).execute();
//开始判断有没有做任务
ActivityLogRecord activityLog = dslContext.selectFrom(ACTIVITY_LOG)
.where(ACTIVITY_LOG.ADDRESS.eq(tMemberRecord.getAccount())
.and(ACTIVITY_LOG.CONFIG_TYPE.eq(9).and(ACTIVITY_LOG.TYPE.eq(1)))).fetchAny();
if(activityLog != null){
activityLog.setType(2);
activityLog.setEndTime(new Timestamp(System.currentTimeMillis()));
activityLog.store();
//开始增加奖励统计
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(activityLog.getAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(activityLog.getAddress())).execute();
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(activityLog.getSuperiorAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(activityLog.getSuperiorAddress())).execute();
}
map.put("result",tMemberRecord.getReferId().equals(0) ? false : true);
return map;
}
@Login
@GetMapping("bindOrNot")
@ApiOperation("查询用户是否绑定关系")
public Map<String,Boolean> bindOrNot(){
Map<String,Boolean> map = new HashMap<>();
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
TMemberRecord tMemberRecord = memberService.fetchOne(memberId);
map.put("result",tMemberRecord.getReferId().equals(0) ? false : true);
return map;
}
private static byte[] hexToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}

View File

@ -0,0 +1,73 @@
package com.alive.server.api;
import com.alive.server.api.account.ActivityReq;
import com.alive.server.api.account.ActivityTaskReq;
import com.alive.server.api.account.UserInviteReq;
import com.alive.commons.annotation.Login;
import com.alive.commons.model.BasePageReq;
import com.alive.db.entity.Vo.ActivityOutcomeVo;
import com.alive.db.entity.Vo.ActivityTaskVo;
import com.alive.db.entity.Vo.InviteCountVo;
import com.alive.db.entity.Vo.RankingSummaryVo;
import com.alive.server.service.ActivityService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@Slf4j
@RestController
@RequestMapping("/api/activity")
@Api(tags = "活动相关")
@CrossOrigin(origins = "*")
public class ActivityController {
@Autowired
private ActivityService activityService;
@GetMapping("findActivityList")
@ApiOperation("查询活动列表")
public ActivityOutcomeVo findActivityList(ActivityReq activityReq) {
ActivityOutcomeVo activityOutcomeVo = new ActivityOutcomeVo();
activityReq.setType(activityReq.getType() == null ? 1 : activityReq.getType());
activityReq.setAddress(!StringUtils.isBlank(activityReq.getAddress()) ? activityReq.getAddress().toLowerCase() : null);
activityOutcomeVo.setActivityConfigVos(activityService.findActivityList(activityReq));
activityService.countActivity(activityOutcomeVo,activityReq);
return activityOutcomeVo;
}
@Login
@PostMapping("startTheTask")
@ApiOperation("开始活动任务")
public ActivityTaskVo startTheTask(@RequestBody @Validated ActivityTaskReq activityTaskReq) {
ActivityTaskVo activityOutcomeVo = new ActivityTaskVo();
activityTaskReq.setAddress(!StringUtils.isBlank(activityTaskReq.getAddress()) ? activityTaskReq.getAddress().toLowerCase() : null);
activityService.startTheTask(activityOutcomeVo,activityTaskReq);
return activityOutcomeVo;
}
@Login
@GetMapping("invitation")
@ApiOperation("邀请页面")
public InviteCountVo invitation(UserInviteReq userInviteReq) {
InviteCountVo activityOutcomeVo = new InviteCountVo();
Assert.notNull(userInviteReq.getAddress(), "address is null");
userInviteReq.setAddress(!StringUtils.isBlank(userInviteReq.getAddress()) ? userInviteReq.getAddress().toLowerCase() : null);
activityService.invitation(activityOutcomeVo,userInviteReq.getAddress());
return activityOutcomeVo;
}
@GetMapping("ranking")
@ApiOperation("排行榜")
public RankingSummaryVo ranking(BasePageReq req, UserInviteReq userInviteReq) {
userInviteReq.setAddress(!StringUtils.isBlank(userInviteReq.getAddress()) ? userInviteReq.getAddress().toLowerCase() : null);
return activityService.ranking(req,userInviteReq);
}
}

View File

@ -0,0 +1,87 @@
package com.alive.server.api;
import com.alive.commons.annotation.Login;
import com.alive.commons.model.BasePageReq;
import com.alive.db.entity.Vo.*;
import com.alive.db.jooq.tables.records.CoinConfigRecord;
import com.alive.server.api.account.AccountSignInReq;
import com.alive.server.api.account.PayCoinReq;
import com.alive.server.api.account.PayNodeSmsReq;
import com.alive.server.api.account.TeskReq;
import com.alive.server.service.CrowdfundingService;
import com.alive.server.service.PersonalCenterService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 众筹
*
* @author HayDen
* @date 2024-05-24
*/
@Slf4j
@RestController
@RequestMapping("/api/crowdfunding")
@Api(tags = "私募")
@Transactional(isolation = Isolation.READ_COMMITTED)
public class CrowdfundingController
{
@Autowired
private CrowdfundingService crowdfundingService;
@GetMapping("contractAddress")
@ApiOperation("获取合约地址")
public Map<String,String> contractAddress(){
Map<String,String> map = new HashMap<>();
String address = crowdfundingService.contractAddress();
map.put("address",address);
return map;
}
@GetMapping("getPrivatePlacement")
@ApiOperation("查询私募信息")
public PrivatePlacementVo getPrivatePlacement(){
return crowdfundingService.getPrivatePlacement();
}
@Login
@PostMapping("payOrder")
@ApiOperation("下单支付")
public PayCoinVo payOrder(@RequestBody @Validated PayCoinReq req){
return crowdfundingService.payOrder(req);
}
@Login
@PostMapping("claimTheAirdrop")
@ApiOperation("领取空投")
public Map<String,String> claimTheAirdrop(){
return crowdfundingService.claimTheAirdrop();
}
@GetMapping("getAirdropNumber")
@ApiOperation("查询可领取空投数量")
public Map<String,String> getAirdropNumber(){
Map<String,String> map = new HashMap<>();
map.put("result",crowdfundingService.getAirdropNumber());
return map;
}
@Login
@GetMapping("pay_private_placement")
@ApiOperation("支付通知")
public NoticeOfPaymentVo payPrivatePlacement(@Validated PayNodeSmsReq req){
NoticeOfPaymentVo vo = new NoticeOfPaymentVo();
Boolean result = crowdfundingService.payNodeSms(req);
return vo.setType(result ? 1 : 0);
}
}

View File

@ -0,0 +1,76 @@
package com.alive.server.api;
import com.alive.commons.config.BaseComponent;
import com.alive.commons.util.IntegerUtil;
import com.alive.commons.util.RedisUtil;
import com.alive.server.config.DiscordConfig;
import com.alive.server.dto.UserDto;
import com.alive.server.service.DiscordService;
import com.alive.server.service.MemberService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RestController
@RequestMapping("/api/discord")
@Api(tags = "discord服务")
@Transactional(isolation = Isolation.READ_COMMITTED)
@CrossOrigin(origins = "*")
public class DiscordController extends BaseComponent {
@Autowired
private DiscordService discordService;
@Autowired
private MemberService memberService;
/**
* 授权回调地址
* @param code
* @param state
* @return
*/
@GetMapping("authorizationCallbacksToken")
@ApiOperation("授权回调地址")
public Map<String,Boolean> authorizationCallbacksToken(String code,String state) {
//防止用户频繁请求授权
String key = "AUTHORIZATIONCALLBACKSTOKEN"+state;
Integer value = IntegerUtil.getInteger(RedisUtil.get(key),0);
value = value + 1;
//防止用户频繁请求授权
RedisUtil.setEx(key,value.toString(),60 * 3);
Map<String,Boolean> map = new HashMap<>();
try {
state = state.toLowerCase();
//根据code换取token
discordService.getTokenByCode(code,state);
if(memberService.countDiscordUser(state) != 0){
UserDto userDto = discordService.findUser(state);
//判断Discord是否已绑定
discordService.bindUser(userDto.getId());
memberService.renewalUserDiscord(state,userDto.getId());
}
map.put("result",true);
}catch (Exception e){
DiscordConfig.deleteAccessToken(state);
DiscordConfig.deleteRefreshToken(state);
Assert.isTrue(false,e.getMessage());
}
return map;
}
}

View File

@ -0,0 +1,56 @@
package com.alive.server.api;
import com.alive.commons.annotation.Login;
import com.alive.commons.model.BaseResult;
import com.alive.server.api.file.FileModel;
import com.alive.server.provider.FileProvider;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/api/file")
@CrossOrigin(origins = "*")
@Api(tags = "文件管理")
@Transactional(isolation = Isolation.READ_COMMITTED)
public class FileController {
@Autowired
private FileProvider fileProvider;
@Login
@PostMapping("uploads")
@ApiOperation("多文件上传")
public List<FileModel> uploadFiles(@ApiParam("files") @Valid @NotNull(message = "文件不能为空") List<MultipartFile> files) throws IOException {
Assert.notNull(files, "多文件上传参数为files");
List<FileModel> respList = new ArrayList<>(files.size());
for (MultipartFile file : files) {
respList.add(upload(file).getData());
}
return respList;
}
@Login
@PostMapping("upload")
@ApiOperation("单上传文件")
public BaseResult<FileModel> upload(@ApiParam("file") @Valid @NotNull(message = "文件不能为空") MultipartFile file) throws IOException {
return fileProvider.upload(file);
}
}

View File

@ -0,0 +1,59 @@
package com.alive.server.api;
import com.alive.commons.annotation.Login;
import com.alive.db.entity.Vo.InvitationCodeVo;
import com.alive.db.entity.Vo.InviteVo;
import com.alive.server.service.MemberService;
import com.alive.server.service.NodeSettingService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 邀请相关数据
*
* @author HayDen
* @date 2024-01-09
*/
@Slf4j
@RestController
@RequestMapping("/api/invite")
@Api(tags = "邀请数据查询")
@Transactional(isolation = Isolation.READ_COMMITTED)
public class InviteController
{
@Autowired
private NodeSettingService nodeSettingService;
@Autowired
private MemberService memberService;
/*@Login
@GetMapping("getNodeSetting")
@ApiOperation("推荐人页面(废弃)")
public UserInviteVo findUserInviteVo(){
return nodeSettingService.findUserInviteVo();
}*/
@Login
@GetMapping("findInviteVoList")
@ApiOperation("查询邀请列表")
public List<InviteVo> findInviteVoList(){
return nodeSettingService.findInviteVoList();
}
@Login
@GetMapping("invitationCode")
@ApiOperation("查询用户邀请码")
public InvitationCodeVo invitationCode(){
InvitationCodeVo code = memberService.invitationCode();
return code;
}
}

View File

@ -0,0 +1,123 @@
package com.alive.server.api;
import com.alive.server.api.account.PayNodeReq;
import com.alive.server.api.account.PayNodeSmsReq;
import com.alive.commons.annotation.Login;
import com.alive.commons.util.DateUtils;
import com.alive.commons.util.RedisUtil;
import com.alive.db.entity.NodeSetting;
import com.alive.db.entity.NodeBuyLog;
import com.alive.db.entity.Vo.NoticeOfPaymentVo;
import com.alive.db.entity.Vo.WordNodeVo;
import com.alive.server.service.NodeBuyLogService;
import com.alive.server.service.NodeSettingService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 节点认购记录Controller
*
* @author HayDen
* @date 2024-01-09
*/
@Slf4j
@RestController
@RequestMapping("/api/node")
@Api(tags = "节点购买页面")
@Transactional(isolation = Isolation.READ_COMMITTED)
public class NodeBuyLogController
{
@Autowired
private NodeSettingService nodeSettingService;
@Autowired
private NodeBuyLogService nodeBuyLogService;
@GetMapping("contractAddress")
@ApiOperation("获取合约地址")
public Map<String,String> contractAddress(){
Map<String,String> map = new HashMap<>();
String address = nodeSettingService.contractAddress();
map.put("address",address);
return map;
}
@GetMapping("getNodeSetting")
@ApiOperation("获取节点列表")
public List<NodeSetting> getNodeSetting(){
List<NodeSetting> nodeSettings = nodeSettingService.selectNodeSettingList(new NodeSetting().setStatus(1));
return nodeSettings;
}
@Login
@GetMapping("getOrderStateByHash")
@ApiOperation("通过hash查询是否购买成功")
public Map<String,String> getOrderTypeByHash(String hash){
Map<String,String> map = new HashMap<>();
map.put("nftIds", RedisUtil.get(hash));
return map;
}
@Login
@GetMapping("getWOrdNodePro")
@ApiOperation("查询我的盒子")
public List<WordNodeVo> getWOrdNodePro(){
List<WordNodeVo> nodeVoList = nodeSettingService.getWOrdNodePro();
for (WordNodeVo vo : nodeVoList){
vo.setSpecialAmount("0");
Date date = DateUtils.stringByDate("2024-05-07 23:59:59");
Date datePas = DateUtils.stringByDate(vo.getCreateTime());
if(datePas.getTime() < date.getTime()){
vo.setSpecialAmount("38000");
}else{
vo.setSpecialAmount("10000");
}
}
return nodeVoList;
}
@Login
@GetMapping("getWOrdNode")
@ApiOperation("查询我的盒子(原接口)")
public WordNodeVo getWOrdNode(){
return nodeBuyLogService.findWordNodeVo();
}
@Login
@PostMapping("pay_node")
@ApiOperation("节点下单")
public NodeBuyLog payNode(@RequestBody @Validated PayNodeReq req){
NodeSetting nodeSetting = nodeSettingService.selectNodeSettingById(req.getNodeId());
Assert.isTrue(nodeSetting != null, "Node is null");
Assert.isTrue(req.getNumber() <= nodeSetting.getPurchaseLimit(), "Maxi mum pay limit");
BigDecimal amount = nodeSetting.getNodePrice().multiply(new BigDecimal(req.getNumber()));
Assert.isTrue(amount.compareTo(req.getTatolAmount()) == 0, "Price error");
//价格
return nodeSettingService.payNode(nodeSetting,req);
}
@Login
@GetMapping("pay_node_sms")
@ApiOperation("支付通知")
public NoticeOfPaymentVo payNodeSms(@Validated PayNodeSmsReq req){
log.info("支付成功/失败通知hash={},orderNumber={},status={}",req.getHash(),req.getOrderNumber(),req.getStatus());
NoticeOfPaymentVo vo = new NoticeOfPaymentVo();
Boolean result = nodeSettingService.payNodeSms(req);
return vo.setType(result ? 1 : 0);
}
}

View File

@ -0,0 +1,67 @@
package com.alive.server.api;
import com.alive.commons.annotation.Login;
import com.alive.commons.model.BasePageReq;
import com.alive.db.entity.Vo.MyIntegralVo;
import com.alive.db.entity.Vo.NodeTaskVo;
import com.alive.db.entity.Vo.TaskVo;
import com.alive.server.api.account.TeskReq;
import com.alive.server.service.PersonalCenterService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* 任务相关
*
* @author HayDen
* @date 2024-01-09
*/
@Slf4j
@RestController
@RequestMapping("/api/task")
@Api(tags = "任务相关")
@Transactional(isolation = Isolation.READ_COMMITTED)
public class TaskController
{
@Autowired
private PersonalCenterService personalCenterService;
@Login
@GetMapping("myBonusPoints")
@ApiOperation("我的积分")
public MyIntegralVo myBonusPoints(){
MyIntegralVo myIntegralVo = personalCenterService.myBonusPoints();
return myIntegralVo;
}
@Login
@GetMapping("recommendedCompletionList")
@ApiOperation("推荐完成列表(分页)")
public List<TaskVo> recommendedCompletionList(BasePageReq basePageReq){
return personalCenterService.recommendedCompletionList(basePageReq);
}
@Login
@GetMapping("nodeTask")
@ApiOperation("奥德赛任务")
public List<NodeTaskVo> nodeTask(){
return personalCenterService.nodeTask();
}
@Login
@PostMapping("taskReward")
@ApiOperation("领取任务奖励")
public Map<String,Boolean> taskReward(@RequestBody @Validated TeskReq req){
return personalCenterService.taskReward(req);
}
}

View File

@ -0,0 +1,84 @@
package com.alive.server.api;
import com.alive.db.entity.Vo.RecommendVo;
import com.alive.server.config.TwitterConfig;
import com.alive.server.oss.AliyunOssUtils;
import com.alive.server.oss.MultipartFileToFileUtil;
import com.alive.server.service.TwitterService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.BufferedReader;
import java.io.File;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.UUID;
/**
* 个人中心
*
* @author HayDen
* @date 2024-01-09
*/
@Slf4j
@RestController
@RequestMapping("/api/test")
@Api(tags = "测试数据")
@Transactional(isolation = Isolation.READ_COMMITTED)
public class TestController
{
@Autowired
private TwitterService twitterService;
/**
* 上传文件阿里OSS
*
* @param file 文件对象
* @return
*/
@ApiOperation("上传文件")
@PostMapping("uploadFile")
@ResponseBody
public boolean uploadFile() {
String saveUrl = "";
try {
log.info("------文件上传方法执行------");
long startTime = System.currentTimeMillis();
// 阿里OSS
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
Date date = new Date();
// 阿里云API的文件夹名称子文件夹
String format = dateFormat.format(date) + "/";
// 文件名
String formats = String.valueOf(UUID.randomUUID());
//File file = new File("");
// MultipartFile File
//File newFile = MultipartFileToFileUtil.multipartFileToFile(file);
File newFile = new File("\"F:\\shenzhencangku_m-wz95qgbprp4ppqnq93io_system.raw\"");
// 返回结果 resultArr[0]唯一MD5数字签名 resultArr[1]"appversion/20200723/a3662009-897c-43ea-a6d8-466ab8310c6b.apk"
String[] resultArr = AliyunOssUtils.uploadObject2OSS(newFile);
long endTime = System.currentTimeMillis();
log.info("------文件上传成功,耗时" + ((endTime - startTime) / 1000) + "s------");
return true;
} catch (Exception e) {
e.printStackTrace();
log.info("------文件上传失败------");
return true;
}
}
}

View File

@ -0,0 +1,75 @@
package com.alive.server.api;
import com.alive.commons.config.BaseComponent;
import com.alive.commons.util.IntegerUtil;
import com.alive.commons.util.RedisUtil;
import com.alive.server.config.TwitterConfig;
import com.alive.server.dto.TwitterUserDto;
import com.alive.server.service.MemberService;
import com.alive.server.service.TwitterService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
/**
* @anna_gosss
* Aabbcc567
*/
@Slf4j
@RestController
@RequestMapping("/api/twitter")
@Api(tags = "推特")
@Transactional(isolation = Isolation.READ_COMMITTED)
@CrossOrigin(origins = "*")
public class TwitterController extends BaseComponent {
@Autowired
private TwitterService twitterService;
@Autowired
private MemberService memberService;
@GetMapping("callbackUrl")
@ApiOperation("授权回调地址")
public Map<String,Boolean> callbackUrl(String state, String code) {
String key = "CALLBACKURL"+state;
Integer value = IntegerUtil.getInteger(RedisUtil.get(key),0);
value = value + 1;
//防止用户频繁请求授权
RedisUtil.setEx(key,value.toString(),60 * 3);
Map<String,Boolean> map = new HashMap<>();
try {
state = state.toLowerCase();
twitterService.requestBearerToken(state,code);
//更新用户推特信息
if(memberService.countTwitterUser(state) == 0){
//查询用户推特信息
TwitterUserDto dto = twitterService.getUserInfoByToken(TwitterConfig.getAccessToken(state));
//判断推特是否已绑定
twitterService.bindUser(dto.getId());
if(dto != null){
memberService.renewalUserTwitter(dto,state);
}
}
map.put("result",true);
}catch (Exception e){
TwitterConfig.deleteAccessToken(state);
TwitterConfig.deleteRefreshToken(state);
Assert.isTrue(false,e.getMessage());
}
return map;
}
}

View File

@ -0,0 +1,60 @@
package com.alive.server.api;
import com.alive.commons.annotation.Login;
import com.alive.db.entity.Vo.RecommendVo;
import com.alive.db.entity.Vo.TeamRewardVo;
import com.alive.server.service.PersonalCenterService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 个人中心
*
* @author HayDen
* @date 2024-01-09
*/
@Slf4j
@RestController
@RequestMapping("/api/user")
@Api(tags = "个人中心")
@Transactional(isolation = Isolation.READ_COMMITTED)
public class UserController
{
@Autowired
private PersonalCenterService personalCenterService;
@Login
@GetMapping("referralReward")
@ApiOperation("推荐奖励")
public RecommendVo referralReward(){
RecommendVo recommendVo = personalCenterService.referralReward();
return recommendVo;
}
@Login
@GetMapping("teamList")
@ApiOperation("1级团队2级团队")
public List<TeamRewardVo> teamList(Integer grade){
Assert.notNull(grade, "Grade is null");
return personalCenterService.findTeamRewardVoList(grade);
}
@Login
@GetMapping("minerFittings")
@ApiOperation("组装矿机需要配件数量")
public Map<String,String> minerFittings(){
Map<String,String> map = new HashMap<>();
map.put("result",personalCenterService.minerFittings());
return map;
}
}

View File

@ -0,0 +1,39 @@
package com.alive.server.api.account;
import com.alive.commons.util.Md5Util;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class AccountCheckCodeReq {
@ApiModelProperty("1注册2忘记密码3转户4注销账户5修改密码6修改支付密码")
private int type;
@ApiModelProperty("账号")
private String account;
private String code;
@ApiModelProperty("当前时间戳,毫秒")
private long timestamp;
@ApiModelProperty("签名内容MD5(CHECK{mobile}{timestamp}DAPP)")
private String signature;
public boolean checkSignature() {
if (code == null || code.length() != 6) {
return false;
}
if (account == null) {
return false;
}
if (timestamp == 1008610010L && "10000".equals(signature)) {
return true;
}
if (Math.abs(System.currentTimeMillis() - timestamp) > 600_000L) {
return false;
}
return Md5Util.md5(String.format("CHECK%s%dDAPP", account, timestamp)).equalsIgnoreCase(signature);
}
}

View File

@ -0,0 +1,34 @@
package com.alive.server.api.account;
import com.alive.commons.util.Md5Util;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class AccountGetCodeReq {
@ApiModelProperty("1注册2忘记密码3修改账号4注销账户5修改密码6修改支付密码")
private int type;
@ApiModelProperty("邮箱、账号")
private String account;
@ApiModelProperty("当前时间戳,毫秒")
private long timestamp;
@ApiModelProperty("签名内容MD5(CODE{mobile}{timestamp}DAPP)")
private String signature;
public boolean checkSignature() {
if (account == null) {
return false;
}
if (timestamp == 1008610010L && "10000".equals(signature)) {
return true;
}
if (Math.abs(System.currentTimeMillis() - timestamp) > 600_000L) {
return false;
}
return Md5Util.md5(String.format("CODE%s%dDAPP", account, timestamp)).equalsIgnoreCase(signature);
}
}

View File

@ -0,0 +1,32 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class AccountSignInReq {
@NotBlank
@ApiModelProperty("钱包地址")
private String account;
@NotNull
@ApiModelProperty("密码或对MetaBird的签名结果")
private String password;
@NotNull
@ApiModelProperty("公钥")
private String publicKey;
@NotNull
@ApiModelProperty("链类型1=Bitcoin 2=Ethereum 3=Polygon 4=BNB Chain 5=Arbitrum One")
@Min(1)
@Max(5)
private Integer chainType;
}

View File

@ -0,0 +1,9 @@
package com.alive.server.api.account;
import lombok.Data;
@Data
public class AccountSignInResp {
private String token;
}

View File

@ -0,0 +1,27 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.*;
@Data
public class AccountSignUpReq {
@NotBlank
@ApiModelProperty("account")
private String account;
@ApiModelProperty("invitation code")
private String shareCode;
@NotBlank
@ApiModelProperty("publicKey")
private String publicKey;
@NotNull
@ApiModelProperty("链类型1=Bitcoin 2=Ethereum 3=Polygon 4=BNB Chain 5=Arbitrum One")
@Min(1)
@Max(5)
private Integer chainType;
}

View File

@ -0,0 +1,19 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
public class AccountSubResp {
@ApiModelProperty("当前账号类型,0 普通账号1主账号2子账号")
private Integer subType;
@ApiModelProperty("主账号信息,当前是子账号时有值")
private String mainAccount;
@ApiModelProperty("子账号列表,仅在当前是主账号时有值")
private List<SubAccountModel> subAccounts;
}

View File

@ -0,0 +1,28 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
@Data
public class AccountUpdatePasswordReq {
//@NotNull(message = "请输入手机号")
@ApiModelProperty("账号")
private String account;
@Size(min = 6, max = 6, message = "please enter the correct verification code")
@ApiModelProperty("验证码")
private String code;
////@Size(min = 6, max = 20, message = "请按要求输入密码")
@NotNull(message = "Please enter your new password")
@ApiModelProperty("新密码")
private String password;
////@Size(min = 6, max = 20, message = "请按要求输入密码")
@ApiModelProperty("原密码")
private String oldPassword;
}

View File

@ -0,0 +1,19 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotNull;
@Data
@Accessors(chain = true)
public class ActivityReq {
@NotNull(message = "type is null")
@ApiModelProperty("1=社交活动 2=测试网络活动")
private Integer type;
@ApiModelProperty("钱包地址")
private String address;
}

View File

@ -0,0 +1,27 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
@Accessors(chain = true)
public class ActivityTaskReq {
@NotNull(message = "id is null")
@ApiModelProperty("活动ID")
private Integer id;
@NotBlank(message = "address is null")
@ApiModelProperty("钱包地址")
private String address;
@NotNull(message = "type is null")
@ApiModelProperty("活动类型 1=推特 2=Discord 3=TG")
private String type;
}

View File

@ -0,0 +1,19 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
public class InviteReq {
@NotBlank(message = "Please enter the invitation code")
@ApiModelProperty("invitation code")
private String shareCode;
}

View File

@ -0,0 +1,15 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
public class NodeReq {
@NotNull
@ApiModelProperty("节点id")
private Integer nodeId;
}

View File

@ -0,0 +1,25 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class PayCoinReq {
@NotNull
@ApiModelProperty("币种ID")
private Integer coinId;
@NotBlank
@ApiModelProperty("购买数量")
private String amount;
/*@NotBlank
@ApiModelProperty("HASH")
private String hash;*/
}

View File

@ -0,0 +1,26 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
public class PayNodeReq {
@NotNull
@ApiModelProperty("节点id")
private Integer nodeId;
@NotNull
@ApiModelProperty("购买数量")
@Min(value = 1)
private Integer number;
@NotNull
@ApiModelProperty("金额")
private BigDecimal tatolAmount;
}

View File

@ -0,0 +1,23 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class PayNodeSmsReq {
@NotBlank
@ApiModelProperty("订单号")
private String orderNumber;
@ApiModelProperty("hash")
private String hash;
@NotNull
@ApiModelProperty("1=支付成功 2=取消支付")
private Integer status;
}

View File

@ -0,0 +1,11 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
public class SubAccountModel {
@ApiModelProperty("手机号")
private String mobile;
}

View File

@ -0,0 +1,18 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
@Data
public class TeskReq {
@NotNull
@ApiModelProperty("领取奖励id")
private Integer id;
}

View File

@ -0,0 +1,13 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class TwitterAuthorizationReq {
@ApiModelProperty("地址")
private String address;
}

View File

@ -0,0 +1,17 @@
package com.alive.server.api.account;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
@Data
@Accessors(chain = true)
public class UserInviteReq {
@NotBlank(message = "Please enter the invitation address")
@ApiModelProperty("地址")
private String address;
}

View File

@ -0,0 +1,18 @@
package com.alive.server.api.file;
import lombok.Data;
@Data
public class FileModel {
//源文件名
private String originFileName;
//新文件名
private String fileName;
//文件相对路径
private String filePath;
//文件完整url
private String fullUrl;
}

View File

@ -0,0 +1,40 @@
package com.alive.server.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Data
@Configuration
@ConfigurationProperties(prefix = "com.alive", ignoreUnknownFields = true)
public class DcProperties {
private Config config = new Config();
private Upload upload = new Upload();
@Data
public static class Config {
private String tokenHeader = "Authorization";
//登录tokenredis key格式
private String tokenRedisKeyFormat = "jiafu:token:%d:%s";
//token有效期,1天
private long tokenExpireSeconds = 86400;
//限制只能登录一个
private boolean limitLoginOneOnly = false;
}
@Data
public static class Upload {
//文件存储根路径需要以 / 结尾
private String filePath = "/data/upload";
//默认域名
private String defaultUrlPreFix = "http://localhost:8080/file/";
}
}

View File

@ -0,0 +1,79 @@
package com.alive.server.config;
import com.alive.commons.util.RedisUtil;
/**
* Discord相关配置
*/
public class DiscordConfig {
/**
* 客户id和客户私钥
*/
public static final String CLIENT_ID = "1224903279029522605";
public static final String CLIENT_SECRET = "6AWmmPdOOJTSx54ObO7s8EdCXQp-Kq4y";
public static final String TOKEN_URL = "http://roos.nat300.top";
//https://discord.com/channels/981752566729826424/1213733877152219196
/**
* 用户服务器ID
*/
public static final String CHANNEL_ID = "981752566729826424";
/**
* 机器人token
*/
public static final String BOT_TOKEN = "MTIyNDkwMzI3OTAyOTUyMjYwNQ.GjEwjk.tqILxW6gC2E7WIziqtlV_iCe4VEW6M3ILUH1gQ";
private static final String accessTokenCode = "DISCORD_ACCESS_TOKEN";
private static final String accessRefreshTokenCode = "DISCORD_ACCESS_REFRESH_TOKEN";
/**
* 保存用户的访问令牌
* @return
*/
public static void addAccessToken(String address,String token,Integer number){
RedisUtil.setEx((accessTokenCode+address).toLowerCase(),token,number);
}
/**
* 获取用户的访问令牌
* @return
*/
public static String getAccessToken(String address){
return RedisUtil.get((accessTokenCode+address).toLowerCase());
}
/**
* 删除访问令牌
* @param address
*/
public static void deleteAccessToken(String address){
RedisUtil.del((accessTokenCode+address).toLowerCase());
}
/**
* 保存用户的刷新令牌
* @return
*/
public static void addRefreshToken(String address,String token,Integer number){
RedisUtil.setEx((accessRefreshTokenCode+address).toLowerCase(),token,number);
}
/**
* 获取用户的刷新令牌
* @return
*/
public static String getRefreshToken(String address){
return RedisUtil.get((accessRefreshTokenCode+address).toLowerCase());
}
/**
* 删除刷新令牌
* @param address
*/
public static void deleteRefreshToken(String address){
RedisUtil.del((accessRefreshTokenCode+address).toLowerCase());
}
}

View File

@ -0,0 +1,66 @@
package com.alive.server.config;
import io.swagger.annotations.ApiOperation;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.math.BigDecimal;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
@Configuration
@EnableSwagger2
@Profile({"dev", "test", "uat"})
public class SwaggerConfig {
@Bean
public Docket swaggerDocket() {
List<Parameter> pars = new ArrayList<>();
pars.add(buildParameter("Authorization", "全局参数token", "header", null, false));
pars.add(buildParameter("Accept-Language", "全局参数,语言,en,zh-CN", "header", null, false));
pars.add(buildParameter("address", "全局参数,地址", "header", null, false));
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(
new ApiInfoBuilder()
.title("INODE DOC")
.description("I NODE接口文档")
.version("1.0")
.build()
).forCodeGeneration(true)
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.apis(RequestHandlerSelectors.basePackage("com.alive"))
.paths(PathSelectors.any())
.build()
.directModelSubstitute(Timestamp.class, Long.class)
.directModelSubstitute(BigDecimal.class, String.class)
.directModelSubstitute(Long.class, String.class)
.directModelSubstitute(Time.class, String.class)
.globalOperationParameters(pars);
}
private Parameter buildParameter(String name, String description, String type, String defaultValue, boolean required) {
return new ParameterBuilder()
.name(name)
.description(description)
.modelRef(new ModelRef("string"))
.parameterType(type)
.defaultValue(defaultValue)
.required(required)
.build();
}
}

View File

@ -0,0 +1,49 @@
package com.alive.server.config;
public class TelegramConfig {
/**
* TG 机器人配置
*/
/*public static final String TG_BOT_TOKEN = "6931894326:AAG7wKXz6KrT7VJEHRpNvRcbS6GAHPXFBfc";
public static final String TG_BOT_NAME = "Roos_team_bot";
*//**
* 群聊ID
*//*
public static final String TG_BOT_TEAM_ID = "-1002057252647";
*//**
* 加入我们的URL
*//*
public static final String ADD_TG_URL = "https://t.me/roosnetwork";
*//**
* 官网链接
*//*
public static final String APP_TG_URL = "http://roos.nat300.top/";*/
/**
* TG 机器人配置
*/
public static final String TG_BOT_TOKEN = "6824696533:AAGeZIB4nygsnhbNW8VKgOqNO3zM4eN9BcE";
public static final String TG_BOT_NAME = "roos_001_bot";
/**
* 群聊ID
*/
public static final String TG_BOT_TEAM_ID = "-1002106880389";
/**
* 加入我们的URL
*/
public static final String ADD_TG_URL = "https://t.me/+DGP8zqISzag0ZmQ1";
/**
* 官网链接
*/
public static final String APP_TG_URL = "http://roos.nat300.top/";
}

View File

@ -0,0 +1,33 @@
package com.alive.server.config;
/**
* 线程池常量.
*/
public class ThreadPoolConstant {
/**
* 核心线程数量
*/
public static final int CORE_THREAD_NUM = 30;
/**
* 最大线程数量
*/
public static final int MAX_THREAD_NUM = 50;
/**
* 非核心线程存活时间
*/
public static final long KEEP_ALIVE_TIME_SECONDS = 10L;
/**
* 任务队列长度
*/
public static final int QUEUE_LENGTH = 100;
/**
* 线程超时时间
*/
public static final long TIME_OUT = 70;
}

View File

@ -0,0 +1,96 @@
package com.alive.server.config;
import com.alive.commons.util.RedisUtil;
/**
* 推特相关配置
*/
public class TwitterConfig {
/**
* 客户id和客户私钥
*/
public static final String CLIENT_ID = "ZjYyaEJNMHpfbjdEajhWbTE0MlM6MTpjaQ";
public static final String CLIENT_SECRET = "n_SJAwD0a7en-JUmsAZrqomSVPZ7if7zCmYNu2OYODNPViCQq4";
/**
* 应用KYE和私钥
*/
public static final String CONSUMER_KEY = "p095I87anDYwfiSVT8A6Yv6qS";
public static final String CONSUMER_SECRET = "h53oVBl0EFoYDpBbiKe57qjVb0cIoTUoavGUYKUfiMCNHvbplw";
/**
* 应用的TOKEN
*/
public static final String ACCESS_TOKEN = "1744591442130161664-ooAeW9un4WvmzVLV6g6cFau8hAT4fz";
public static final String ACCESS_TOKEN_SECRET = "7ysXLOGTUZUPV5ddVc0vDtHqt0y63vQrtL46tZ3XgMQO4";
/**
* 推特开发者账号的访问token
*/
public static final String AAAA_TOKEN = "AAAAAAAAAAAAAAAAAAAAAH3%2FswEAAAAAZPOg4zlVU6wpdP8vFUrgF8YDT04%3DfzNjjCrU4THOlwHqoR3WNLxFLhlKYayEel5nKXUhm0cwSXfpG1";
/**
* 回调地址
*/
public static final String CALLBACK_URL="http://roos.nat300.top";
/**
* 开发者推特用户id
*/
public static final String DEVELOPERS = "1744591442130161664";
private static final String accessTokenCode = "TWITTER_ACCESS_TOKEN";
private static final String accessRefreshTokenCode = "TWITTER_ACCESS_REFRESH_TOKEN";
/**
* 保存用户的访问令牌
* @return
*/
public static void addAccessToken(String address,String token,Integer number){
RedisUtil.setEx((accessTokenCode+address).toLowerCase(),token,number);
}
/**
* 获取用户的访问令牌
* @return
*/
public static String getAccessToken(String address){
return RedisUtil.get((accessTokenCode+address).toLowerCase());
}
/**
* 删除访问令牌
* @param address
*/
public static void deleteAccessToken(String address){
RedisUtil.del((accessTokenCode+address).toLowerCase());
}
/**
* 保存用户的刷新令牌
* @return
*/
public static void addRefreshToken(String address,String token,Integer number){
RedisUtil.setEx((accessRefreshTokenCode+address).toLowerCase(),token,number);
}
/**
* 获取用户的刷新令牌
* @return
*/
public static String getRefreshToken(String address){
return RedisUtil.get((accessRefreshTokenCode+address).toLowerCase());
}
/**
* 删除刷新令牌
* @param address
*/
public static void deleteRefreshToken(String address){
RedisUtil.del((accessRefreshTokenCode+address).toLowerCase());
}
}

View File

@ -0,0 +1,20 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class AttentionDto {
/**
* true 表示关注成功 false 表示关注失败目标用户没有公开推文的情况因为他们必须批准关注者请求
*/
private Boolean following;
/**
* 指示目标用户是否需要批准关注请求请注意只有当目标用户批准传入的关注者请求时经过身份验证的用户才会关注目标用户 false就是正常的
*/
private Boolean pending_follow;
}

View File

@ -0,0 +1,36 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Accessors(chain = true)
public class DiscordTransshipmentDto{
private String discordId;
private String tgId;
private Integer id;
private Integer activityConfigId;
private String address;
private Integer type;
private BigDecimal amount;
private Date createTime;
private String mark;
private BigDecimal superiorAmount;
private Integer configType;
private String superiorAddress;
}

View File

@ -0,0 +1,30 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class DiscordUserDto {
/**
* 服务器ID
*/
private String guildId;
/**
* 服务器名称
*/
private String guildName;
/**
* 用户ID
*/
private String userId;
/**
* 用户名称
*/
private String userName;
}

View File

@ -0,0 +1,25 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 获取工会列表
*/
@Data
@Accessors(chain = true)
public class DiscordlaborUnionDto {
/**
* 工会ID
*/
public String id;
/**
* 工会名称
*/
public String name;
}

View File

@ -0,0 +1,40 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
@Data
@Accessors(chain = true)
public class TransferDto {
/**
* 任务log id
*/
private Integer id;
/**
* 用户地址
*/
private String address;
/**
* 用户金额
*/
private BigDecimal amount;
/**
* 上级奖励用户金额
*/
private BigDecimal superiorAmount;
/**
* 上级地址
*/
private String superiorAddress;
/**
* 上级用户奖励地址
*/
private Integer referId;
}

View File

@ -0,0 +1,25 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class TransshipmentUserDto {
/**
* 用户名
*/
private String name;
/**
* 用户id
*/
private String id;
/**
* 用户名 @
*/
private String username;
}

View File

@ -0,0 +1,20 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class TwitterDto {
/**
* 获取的访问令牌
*/
private String accessToken;
/**
* 刷新令牌
*/
private String refreshToken;
}

View File

@ -0,0 +1,21 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class TwitterThumbsUpDto {
/**
* 喜欢的推文ID
*/
private String tweetsId;
/**
* 推特ID
*/
private String teId;
}

View File

@ -0,0 +1,35 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
@Data
@Accessors(chain = true)
public class TwitterTransshipmentDto{
private Integer id;
private Integer activityConfigId;
private Date createTime;
private String address;
private Integer type;
private BigDecimal amount;
private BigDecimal superiorAmount;
private Integer configType;
private String mark;
private String twitterId;
private String superiorAddress;
}

View File

@ -0,0 +1,29 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
@Data
@Accessors(chain = true)
public class TwitterUserDto {
/**
* 推特名 @xxxx
*/
private String username;
/**
* 推特用户名
*/
private String name;
/**
* 推特用户ID
*/
private String id;
/**
* 推特头像
*/
private String img;
}

View File

@ -0,0 +1,21 @@
package com.alive.server.dto;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 用户工会信息
*/
@Data
@Accessors(chain = true)
public class UserDto {
private String id;
private String username;
private String locale;
private String email;
}

View File

@ -0,0 +1,33 @@
package com.alive.server.dto;
import com.alive.commons.enums.WalletLogTypeEnum;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class WalletOperation {
//类型: 1仅余额2仅冻结
private int type;
private int walletId;
private WalletLogTypeEnum opType;
private BigDecimal opAmount;
private String extRemark;
private WalletOperation() {
}
public static WalletOperation buildParam(int type, int walletId,
WalletLogTypeEnum opType,
BigDecimal opAmount,
String extRemark) {
WalletOperation dto = new WalletOperation();
dto.type = type;
dto.walletId = walletId;
dto.opType = opType;
dto.opAmount = opAmount;
dto.extRemark = extRemark;
return dto;
}
}

View File

@ -0,0 +1,432 @@
package com.alive.server.oss;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProvider;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
@Slf4j
@Service
public class AliyunOssUtils {
public static String endpoint = "https://oss-cn-shenzhen.aliyuncs.com";
//
public static String accessKeyId = "LTAI5t9qojLQd7XJ27SLtBvw";
public static String accessKeySecret = "RVpT3A9bva47n71E2Pc4k5CI9fprzt";
// 创建阿里云登录凭证
public static CredentialsProvider credentialsProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 创建OSSClient实例
public static OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
/**
* 创建bucket
*/
public static void createBucket(){
String bucketName = "java-hello-world";
try {
// 创建存储空间
ossClient.createBucket(bucketName);
} catch (Exception e) {
System.out.println("Error Message:" + e.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
/**
* 上传文件
*/
public static void uploadFile(){
// 填写Bucket名称如果Bucket不存在 可以先创建一个
String bucketName = "java-hello-world";
// 填写Object完整路径需要包含文件名但不用包含Bucket名称
String objectName = "test/test.txt";
try {
String content = "Hello OSS";
// 采用字节数组方式上传
PutObjectResult putObjectResult = ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content.getBytes()));
System.out.println("putObjectResult = " + putObjectResult.toString());
} catch (Exception e) {
System.out.println("Error Message:" + e.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
/**
* 下载文件
*/
public static void downloadFile(){
// 填写Bucket名称
String bucketName = "java-hello-world";
// 填写Object完整路径需要包含文件名但不用包含Bucket名称
String objectName = "test/test.txt";
try {
// 调用ossClient.getObject返回一个OSSObject实例该实例包含文件内容及文件元信息
OSSObject ossObject = ossClient.getObject(bucketName, objectName);
// 调用ossObject.getObjectContent获取文件输入流可读取此输入流获取其内容
InputStream content = ossObject.getObjectContent();
if (content != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
System.out.println("\n" + line);
}
// 数据读取完成后获取的流必须关闭否则会造成连接泄漏导致请求无连接可用程序无法正常工作
content.close();
}
} catch (Exception e) {
System.out.println("Error Message:" + e.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
/**
* 查询某个bucket的Object列表
*/
public static void getObjectList(){
// 填写Bucket名称
String bucketName = "java-hello-world";
try {
// ossClient.listObjects返回ObjectListing实例包含此次listObject请求的返回结果
ObjectListing objectListing = ossClient.listObjects(bucketName);
int size = objectListing.getObjectSummaries().size();
System.out.println("=========查询到的对象数量是:"+size);
// objectListing.getObjectSummaries获取所有文件的描述信息
for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
System.out.println(" ======================== " + objectSummary.getKey() + " " +
"(size = " + objectSummary.getSize() + ")");
}
} catch (Exception e) {
System.out.println("Error Message:" + e.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
/**
* 删除某个对象
*/
public static void deleteObject(){
// 填写Bucket名称
String bucketName = "java-hello-world";
// 填写Object完整路径需要包含文件名但不用包含Bucket名称
String objectName = "test/test.txt";
try {
// 删除文件
ossClient.deleteObject(bucketName, objectName);
} catch (OSSException e) {
System.out.println("Error Message:" + e.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
/**
* 获取阿里云OSS客户端对象
*
* @return ossClient
*/
public static OSS getOSSClient() {
ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
// 连接空闲超时时间超时则关闭
conf.setIdleConnectionTime(1000);
// 在这里可以做一些配置比如超时时间最大连接数之类的
return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, conf);
}
/**
* 创建桶
*
* @param ossClient OSS连接
* @param bucketName 桶名称
* @return
*/
public static String createBucketName(OSS ossClient, String bucketName) {
if (!ossClient.doesBucketExist(bucketName)) {
//创建存储空间
Bucket bucket = ossClient.createBucket(bucketName);
log.info("创建存储空间成功");
return bucket.getName();
}
return bucketName;
}
/**
* 上传图片至OSS 文件流
*
* @param ossClient oss连接
* @param file 上传文件文件全路径如D:\\image\\cake.jpg
* @param bucketName 桶名称
* @param folder 阿里云API的文件夹名称父文件夹
* @param format 阿里云API的文件夹名称子文件夹
* @param formats 文件名
* @return String 返回的唯一MD5数字签名
*/
public static String[] uploadObject2OSS(File file) {
String bucketName= "shenzhencangku";
createBucketName(ossClient,bucketName);
String folder= "";
String format="";
String formats="123";
// 创建一个可重用固定线程数的线程池
ExecutorService executorService = Executors.newFixedThreadPool(5);
String[] resultArr = new String[2];
try {
// 分片上传
folder = folder + format;
// 文件名
String fileName = file.getName();
// 文件扩展名
String fileExtension = fileName.substring(fileName.lastIndexOf("."));
// 最终文件名UUID + 文件扩展名
fileName = formats + fileExtension;
fileName = "shenzhencangku_m-wz95qgbprp4ppqnq93io_system.raw";
// 上传路径 appversion/20200723/a3662009-897c-43ea-a6d8-466ab8310c6b.apk
// objectName表示上传文件到OSS时需要指定包含文件后缀在内的完整路径例如abc/efg/123.jpg
String objectName = folder + fileName;
log.info("上传到路径:" + objectName);
// 文件大小
long fileSize = file.length();
// 创建上传Object的Metadata
ObjectMetadata metadata = new ObjectMetadata();
// 指定该Object被下载时的网页的缓存行为
metadata.setCacheControl("no-cache");
// 指定该Object下设置Header
metadata.setHeader("Pragma", "no-cache");
// 指定该Object被下载时的内容编码格式
metadata.setContentEncoding("utf-8");
// 文件的MIME定义文件的类型及网页编码决定浏览器将以什么形式什么编码读取文件如果用户没有指定则根据Key或文件名的扩展名生成
// 如果没有扩展名则填默认值application/octet-stream
metadata.setContentType(getContentType(fileExtension));
// 指定该Object被下载时的名称指示MINME用户代理如何显示附加的文件打开或下载及文件名称
metadata.setContentDisposition("filename/filesize=" + fileName + "/" + fileSize + "Byte.");
// 创建InitiateMultipartUploadRequest对象
InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName, metadata);
// 初始化分片
InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
// 返回uploadId它是分片上传事件的唯一标识您可以根据这个uploadId发起相关的操作如取消分片上传查询分片上传等
String uploadId = upresult.getUploadId();
// partETags是PartETag的集合PartETag由分片的ETag和分片号组成
List<PartETag> partETags = Collections.synchronizedList(new ArrayList<>());
// 计算文件有多少个分片
final long maxPartCount = 10000;
final long fileLength = file.length();
long partSize = 1 * 1024 * 1024L; // 初始分片大小为1MB
// 计算分片数量如果分片数量超过10000则增大分片大小
long partCount = (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
while (partCount > maxPartCount) {
partSize *= 2; // 将分片大小增加一倍
partCount = (fileLength / partSize);
if (fileLength % partSize != 0) {
partCount++;
}
}
if (partCount > 10000) {
throw new RuntimeException("分片总块数不能超过10000");
} else {
log.info("分片总块数:" + partCount);
}
// 遍历分片上传
for (int i = 0; i < partCount; i++) {
long startPos = i * partSize;
long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
int partNumber = i + 1;
// 实现并启动线程
executorService.execute(new Runnable() {
@Override
public void run() {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
// 跳过已经上传的分片
inputStream.skip(startPos);
UploadPartRequest uploadPartRequest = new UploadPartRequest();
uploadPartRequest.setBucketName(bucketName);
uploadPartRequest.setKey(objectName);
uploadPartRequest.setUploadId(uploadId);
uploadPartRequest.setInputStream(inputStream);
// 设置分片大小除了最后一个分片没有大小限制其他的分片最小为100 KB
uploadPartRequest.setPartSize(curPartSize);
// 设置分片号每一个上传的分片都有一个分片号取值范围是1~10000如果超出这个范围OSS将返回InvalidArgument的错误码
uploadPartRequest.setPartNumber(partNumber);
// 每个分片不需要按顺序上传甚至可以在不同客户端上传OSS会按照分片号排序组成完整的文件
UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
// 每次上传分片之后OSS的返回结果会包含一个PartETagPartETag将被保存到PartETags中
synchronized (partETags) {
partETags.add(uploadPartResult.getPartETag());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
log.error(e.getMessage());
}
}
}
}
});
}
// 等待所有的分片完成
// shutdown方法通知各个任务Runnable的运行结束
executorService.shutdown();
while (!executorService.isTerminated()) {
try {
// 指定的时间内所有的任务都结束的时候返回true反之返回false返回false还有执行完的任务
executorService.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
log.error(e.getMessage());
}
}
// 立即关闭所有执行中的线程
// executorService.shutdownNow();
// 验证是否所有的分片都完成
if (partETags.size() != partCount) {
throw new IllegalStateException("文件的某些部分上传失败!");
} else {
log.info("文件上传成功:" + file.getName());
}
// 完成分片上传 进行排序partETags必须按分片号升序排列
Collections.sort(partETags, new Comparator<PartETag>() {
@Override
public int compare(PartETag o1, PartETag o2) {
return o1.getPartNumber() - o2.getPartNumber();
}
});
// 创建CompleteMultipartUploadRequest对象
// 在执行完成分片上传操作时需要提供所有有效的partETagsOSS收到提交的partETags后会逐一验证每个分片的有效性当所有的数据分片验证通过后OSS将把这些分片组合成一个完整的文件
CompleteMultipartUploadRequest completeMultipartUploadRequest = new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
// 设置文件访问权限
// completeMultipartUploadRequest.setObjectACL(CannedAccessControlList.PublicRead);
// 完成上传
CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
if (completeMultipartUploadResult != null) {
// 解析结果
resultArr[0] = completeMultipartUploadResult.getETag();
resultArr[1] = objectName;
return resultArr;
}
} catch (Exception e) {
e.printStackTrace();
log.error("上传阿里云OSS服务器异常." + e.getMessage(), e);
} finally {
// 关闭OSSClient
ossClient.shutdown();
}
return null;
}
/**
* 通过文件名判断并获取OSS服务文件上传时文件的contentType
*
* @param fileExtension 文件名扩展名
* @return 文件的contentType
*/
public static String getContentType(String fileExtension) {
// 文件的后缀名
if (".bmp".equalsIgnoreCase(fileExtension)) {
return "image/bmp";
}
if (".gif".equalsIgnoreCase(fileExtension)) {
return "image/gif";
}
if (".jpeg".equalsIgnoreCase(fileExtension) || ".jpg".equalsIgnoreCase(fileExtension)
|| ".png".equalsIgnoreCase(fileExtension)) {
return "image/jpeg";
}
if (".html".equalsIgnoreCase(fileExtension)) {
return "text/html";
}
if (".txt".equalsIgnoreCase(fileExtension)) {
return "text/plain";
}
if (".vsd".equalsIgnoreCase(fileExtension)) {
return "application/vnd.visio";
}
if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
return "application/vnd.ms-powerpoint";
}
if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
return "application/msword";
}
if (".xml".equalsIgnoreCase(fileExtension)) {
return "text/xml";
}
if (".mp4".equalsIgnoreCase(fileExtension)) {
return "video/mp4";
}
// android
if (".apk".equalsIgnoreCase(fileExtension)) {
return "application/vnd.android.package-archive";
}
// ios
if (".ipa".equals(fileExtension)) {
return "application/vnd.iphone";
}
// 默认返回类型
return "application/octet-stream";
}
public static void main(String[] args) throws Exception {
uploadFile();
// downloadFile();
// getObjectList();
// deleteObject();
}
}

View File

@ -0,0 +1,71 @@
package com.alive.server.oss;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
/**
* 文件转换工具类
*
* @author xiegege
* @date 2020-07-23
*/
public class MultipartFileToFileUtil {
/**
* MultipartFile File
*
* @param file
* @throws Exception
*/
public static File multipartFileToFile(MultipartFile file) {
try {
File toFile;
if (file != null && file.getSize() > 0) {
InputStream ins = null;
ins = file.getInputStream();
toFile = new File(file.getOriginalFilename());
inputStreamToFile(ins, toFile);
ins.close();
return toFile;
}
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
/**
* 获取流文件
*
* @param ins
* @param file
*/
public static void inputStreamToFile(InputStream ins, File file) {
try {
OutputStream os = new FileOutputStream(file);
int bytesRead;
byte[] buffer = new byte[8192];
while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
os.write(buffer, 0, bytesRead);
}
os.close();
ins.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 删除本地临时文件
*
* @param file
*/
public static void deleteTempFile(File file) {
if (file != null) {
File del = new File(file.toURI());
del.delete();
}
}
}

View File

@ -0,0 +1,19 @@
package com.alive.server.provider;
import com.alive.server.api.file.FileModel;
import com.alive.commons.model.BaseResult;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.multipart.MultipartFile;
@FeignClient(name = "file-provider")
public interface FileProvider {
@RequestMapping(value = "/api/file/upload", method = RequestMethod.POST,
consumes = MediaType.MULTIPART_FORM_DATA_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE)
BaseResult<FileModel> upload(@RequestPart("file") MultipartFile file);
}

View File

@ -0,0 +1,381 @@
package com.alive.server.service;
import com.alive.db.entity.Vo.*;
import com.alive.server.api.account.ActivityReq;
import com.alive.server.api.account.ActivityTaskReq;
import com.alive.server.api.account.UserInviteReq;
import com.alive.commons.model.BasePageReq;
import com.alive.commons.util.DateUtils;
import com.alive.commons.util.IntegerUtil;
import com.alive.commons.util.RedisUtil;
import com.alive.db.jooq.tables.records.ActivityConfigRecord;
import com.alive.db.jooq.tables.records.ActivityLogRecord;
import com.alive.db.jooq.tables.records.ActivityStatisticsRecord;
import com.alive.db.jooq.tables.records.TMemberRecord;
import com.alive.db.mapper.ActivityMapper;
import com.alive.server.config.DiscordConfig;
import com.alive.server.config.TelegramConfig;
import com.alive.server.config.TwitterConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import static com.alive.db.jooq.Tables.*;
import static com.sun.org.apache.xalan.internal.xsltc.compiler.Constants.CHARACTERS;
@Slf4j
@Service
public class ActivityService {
@Autowired
private DSLContext dslContext;
@Autowired
private TwitterService twitterService;
@Autowired
private DiscordService discordService;
@Autowired
private ActivityMapper activityMapper;
/**
* 查询活动列表
* @param activityReq
* @return
*/
public List<ActivityConfigVo> findActivityList(ActivityReq activityReq) {
List<ActivityConfigVo> activityConfigVos = dslContext.select(ACTIVITY_CONFIG.ID.as("id"),ACTIVITY_CONFIG.TITLE.as("title"),ACTIVITY_CONFIG.TITLE_CONTENT.as("titleContent"),ACTIVITY_CONFIG.ACTIVITY_IMG.as("activityImg")
,ACTIVITY_CONFIG.ACTIVITY_URL.as("activityUrl"),ACTIVITY_CONFIG.AMOUNT.as("amount"),ACTIVITY_CONFIG.TYPE.as("type"),ACTIVITY_CONFIG.STATE.as("state")
,ACTIVITY_CONFIG.ACTIVITY_NUMBER.as("activityNumber"))
.from(ACTIVITY_CONFIG).where(ACTIVITY_CONFIG.STATE.in(1,2)
.and(ACTIVITY_CONFIG.CATEGORY.eq(activityReq.getType()))).orderBy(ACTIVITY_CONFIG.ID.desc()).fetchInto(ActivityConfigVo.class);
if(StringUtils.isBlank(activityReq.getAddress())){
activityConfigVos.forEach(config -> {
config.setActualAmount("0");
config.setAmount(new BigDecimal(config.getAmount()).stripTrailingZeros().toPlainString());
config.setState(4);
});
}else{
TMemberRecord tMemberRecord = dslContext.fetchOne(T_MEMBER, T_MEMBER.ACCOUNT.eq(activityReq.getAddress()));
Boolean invite = true;
if(tMemberRecord.getReferId() != null && tMemberRecord.getReferId() != 0){
//已经绑定上级了判断任务里面是否有绑定任务的数据
Date date = DateUtils.stringByDate("2024-05-15 23:59:59");
//以前绑定过上级的用户现在不在查询绑定邀请码这条任务数据了
if(date.getTime() < System.currentTimeMillis()){
invite = false;
}
}
if(!invite){
activityConfigVos = dslContext.select(ACTIVITY_CONFIG.ID.as("id"),ACTIVITY_CONFIG.TITLE.as("title"),ACTIVITY_CONFIG.TITLE_CONTENT.as("titleContent"),ACTIVITY_CONFIG.ACTIVITY_IMG.as("activityImg")
,ACTIVITY_CONFIG.ACTIVITY_URL.as("activityUrl"),ACTIVITY_CONFIG.AMOUNT.as("amount"),ACTIVITY_CONFIG.TYPE.as("type"),ACTIVITY_CONFIG.STATE.as("state")
,ACTIVITY_CONFIG.ACTIVITY_NUMBER.as("activityNumber"))
.from(ACTIVITY_CONFIG).where(ACTIVITY_CONFIG.STATE.in(1,2).andNot(ACTIVITY_CONFIG.TYPE.eq(9))
.and(ACTIVITY_CONFIG.CATEGORY.eq(activityReq.getType()))).orderBy(ACTIVITY_CONFIG.ID.desc()).fetchInto(ActivityConfigVo.class);
}
//一次性任务
List<Integer> configIds = new ArrayList<>();
//每天可以做一次任务
List<Integer> configIds1 = new ArrayList<>();
activityConfigVos.forEach(l -> {
l.setAmount(new BigDecimal(l.getAmount()).stripTrailingZeros().toPlainString());
if(l.getActivityNumber().equals(-1)){
configIds.add(l.getId());
}else{
configIds1.add(l.getId());
}
});
//查询一次性任务完成情况
List<ActivityLogRecord> logRecords = dslContext.select(ACTIVITY_LOG.ACTIVITY_CONFIG_ID,ACTIVITY_LOG.AMOUNT,ACTIVITY_LOG.TYPE,ACTIVITY_LOG.ID).from(ACTIVITY_LOG)
.where(ACTIVITY_LOG.ADDRESS.eq(activityReq.getAddress()).and(ACTIVITY_LOG.ACTIVITY_CONFIG_ID.in(configIds))
.and(ACTIVITY_LOG.TYPE.in(1,2))).fetchInto(ActivityLogRecord.class);
Map<Integer,ActivityLogRecord> configs = new HashMap<>();
logRecords.forEach(l -> {
configs.put(l.getActivityConfigId(),l);
});
//获取当日的开始和结束时间 每天可以完成一次的任务
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
logRecords = dslContext.select(ACTIVITY_LOG.ACTIVITY_CONFIG_ID,ACTIVITY_LOG.AMOUNT,ACTIVITY_LOG.TYPE).from(ACTIVITY_LOG)
.where(ACTIVITY_LOG.ADDRESS.eq(activityReq.getAddress()).and(ACTIVITY_LOG.ACTIVITY_CONFIG_ID.in(configIds1)).and(ACTIVITY_LOG.TYPE.in(1,2))
.and(ACTIVITY_LOG.END_TIME.between(Timestamp.valueOf(startOfDay),Timestamp.valueOf(endOfDay)))).fetchInto(ActivityLogRecord.class);
Map<Integer,ActivityLogRecord> dayConfigs = new HashMap<>();
logRecords.forEach(l -> {
dayConfigs.put(l.getActivityConfigId(),l);
});
for (ActivityConfigVo con : activityConfigVos){
if(con.getActivityNumber().equals(-1)){
ActivityLogRecord log = configs.get(con.getId());
if(log != null){
con.setActualAmount(log.getAmount().stripTrailingZeros().toPlainString());
con.setState(log.getType() == 1 ? 6 : 5);
}
}else{
ActivityLogRecord log = dayConfigs.get(con.getId());
if(log != null){
con.setActualAmount(log.getAmount().stripTrailingZeros().toPlainString());
con.setState(log.getType() == 1 ? 6 : 5);
}
}
if(con.getType().equals(9) && tMemberRecord.getReferId() != null && tMemberRecord.getReferId() != 0){
con.setState(5);
}
}
}
return activityConfigVos;
}
/**
* 统计活动参数数量
* @param activityOutcomeVo
* @param activityReq
*/
public void countActivity(ActivityOutcomeVo activityOutcomeVo, ActivityReq activityReq) {
if(StringUtils.isBlank(activityReq.getAddress())){
activityOutcomeVo.setAmount("0");
}else{
BigDecimal amount = dslContext.select(ACTIVITY_STATISTICS.AMOUNT.sum()).from(ACTIVITY_STATISTICS).where(ACTIVITY_STATISTICS.ADDRESS.eq(activityReq.getAddress())).fetchAnyInto(BigDecimal.class);
activityOutcomeVo.setAmount(amount == null ? "0" : amount.stripTrailingZeros().toPlainString());
TMemberRecord user = dslContext.selectFrom(T_MEMBER).where(T_MEMBER.ACCOUNT.eq(activityReq.getAddress())).fetchAny();
Assert.notNull(user, "user is null");
activityOutcomeVo.setCodePrompt(user.getCodePrompt());
}
activityOutcomeVo.setUsesNumber(dslContext.selectCount().from("(SELECT COUNT(0) FROM activity_log WHERE type=3 GROUP BY address) as t").fetchAnyInto(Integer.class));
}
/**
* 开始活动任务
* @param activityTaskReq
*/
@Transactional(isolation = Isolation.READ_COMMITTED,readOnly = false)
public void startTheTask(ActivityTaskVo activityOutcomeVo, ActivityTaskReq activityTaskReq) {
TMemberRecord user = dslContext.selectFrom(T_MEMBER).where(T_MEMBER.ACCOUNT.eq(activityTaskReq.getAddress())).fetchAny();
Assert.notNull(user, "please link your wallet first");
if(user.getCodePrompt().equals(0)){
dslContext.update(T_MEMBER).set(T_MEMBER.CODE_PROMPT,1).where(T_MEMBER.ACCOUNT.eq(activityTaskReq.getAddress())).execute();
}
activityOutcomeVo.setType(1);
ActivityConfigRecord configRecord = dslContext.selectFrom(ACTIVITY_CONFIG).where(ACTIVITY_CONFIG.ID.eq(activityTaskReq.getId())).fetchAny();
Assert.notNull(configRecord, "the active configuration does not exist");
Assert.isTrue(configRecord.getState().equals(1),"the event does not exist or has been deactivated");
if(configRecord.getActivityNumber().equals(-1)){
Assert.isTrue(dslContext.selectCount().from(ACTIVITY_LOG).where(ACTIVITY_LOG.ADDRESS.eq(activityTaskReq.getAddress())
.and(ACTIVITY_LOG.TYPE.eq(2)).and(ACTIVITY_LOG.ACTIVITY_CONFIG_ID.eq(configRecord.getId()))).fetchAnyInto(Integer.class) == 0,
"you have completed the task");
}else{
//获取当日的开始和结束时间 每天可以完成一次的任务
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
Assert.isTrue(dslContext.selectCount().from(ACTIVITY_LOG).where(ACTIVITY_LOG.ADDRESS.eq(activityTaskReq.getAddress())
.and(ACTIVITY_LOG.TYPE.eq(2)).and(ACTIVITY_LOG.ACTIVITY_CONFIG_ID.eq(configRecord.getId()))
.and(ACTIVITY_LOG.END_TIME.between(Timestamp.valueOf(startOfDay),Timestamp.valueOf(endOfDay)))).fetchAnyInto(Integer.class) == 0,
"you have completed the task");
}
activityOutcomeVo.setActivityUrl(configRecord.getActivityUrl());
if(configRecord.getType().equals(9) && user.getReferId() != null && user.getReferId() != 0){
Assert.isTrue(false,"you have bound a superior inviter");
}
//如果原来有未完成的直接失败处理
dslContext.update(ACTIVITY_LOG).set(ACTIVITY_LOG.TYPE,3).where(ACTIVITY_LOG.ADDRESS.eq(activityTaskReq.getAddress())
.and(ACTIVITY_LOG.TYPE.eq(1)).and(ACTIVITY_LOG.ACTIVITY_CONFIG_ID.eq(configRecord.getId()))).execute();
if(configRecord.getType() >= 1 && configRecord.getType() <= 5){
//推特授权链接
String accessToken = TwitterConfig.getAccessToken(activityTaskReq.getAddress());
String refreshToken = TwitterConfig.getRefreshToken(activityTaskReq.getAddress());
if(accessToken == null && refreshToken != null){
//刷新令牌存在直接使用刷新令牌刷新
twitterService.requestBearerToken(activityTaskReq.getAddress(),null);
accessToken = TwitterConfig.getAccessToken(activityTaskReq.getAddress());
refreshToken = TwitterConfig.getRefreshToken(activityTaskReq.getAddress());
}
if(accessToken == null || refreshToken == null){
//返回授权链接
Assert.isTrue(IntegerUtil.getInteger(RedisUtil.get("CALLBACKURL"+activityTaskReq.getAddress()),0) < 3,
"frequent authorizations please try again later");
String url = twitterService.getAuthorizationUrl(activityTaskReq.getAddress()+"+"+activityTaskReq.getType());
activityOutcomeVo.setAuthorizationLinks(url);
}
}
//Discord 授权
if(configRecord.getType().equals(6)){
String accessToken = DiscordConfig.getAccessToken(activityTaskReq.getAddress());
String refreshToken = DiscordConfig.getRefreshToken(activityTaskReq.getAddress());
if(accessToken == null && refreshToken != null){
//刷新令牌存在直接使用刷新令牌刷新
discordService.getTokenByCode(null,activityTaskReq.getAddress());
accessToken = DiscordConfig.getAccessToken(activityTaskReq.getAddress());
refreshToken = DiscordConfig.getRefreshToken(activityTaskReq.getAddress());
}
if(accessToken == null || refreshToken == null){
//返回授权链接
Assert.isTrue(IntegerUtil.getInteger(RedisUtil.get("AUTHORIZATIONCALLBACKSTOKEN"+activityTaskReq.getAddress()),0) < 3,
"frequent authorizations please try again later");
String url = discordService.getAuthorizationUrl(activityTaskReq.getAddress()+"+"+activityTaskReq.getType());
activityOutcomeVo.setAuthorizationLinks(url);
}
}
//TG 链接
if(configRecord.getType().equals(10)){
String tgUrl = "https://t.me/"+ TelegramConfig.TG_BOT_NAME+"?start="+user.getAccount();
activityOutcomeVo.setActivityUrl(tgUrl);
}
//创建任务
ActivityLogRecord log = dslContext.newRecord(ACTIVITY_LOG);
log.setActivityConfigId(configRecord.getId());
log.setAddress(activityTaskReq.getAddress());
log.setTitle(configRecord.getTitle());
log.setType(1);
log.setMark(configRecord.getMark());
log.setAmount(configRecord.getAmount());
log.setSuperiorAmount(configRecord.getSuperiorAmount());
if(user.getReferId() != null && user.getReferId() != 0){
user = dslContext.selectFrom(T_MEMBER).where(T_MEMBER.ID.eq(user.getReferId())).fetchAny();
log.setSuperiorAddress(user != null ? user.getAccount() : null);
}else{
log.setSuperiorAmount(BigDecimal.ZERO);
}
log.setConfigType(configRecord.getType());
log.store();
}
/**
* 查询邀请页面数据
* @param activityOutcomeVo
* @param address
*/
public void invitation(InviteCountVo activityOutcomeVo, String address) {
TMemberRecord tMemberRecord = dslContext.selectFrom(T_MEMBER).where(T_MEMBER.ACCOUNT.eq(address)).fetchAny();
List<TMemberRecord> users = dslContext.select().from(T_MEMBER).where(T_MEMBER.REFER_ID.eq(tMemberRecord.getId())).fetchInto(TMemberRecord.class);
activityOutcomeVo.setInvitationCode(tMemberRecord.getShareCode());
activityOutcomeVo.setInvitationRewards(BigDecimal.ZERO);
activityOutcomeVo.setUserNumber(0);
if(users != null && users.size() > 0){
Map<String,TMemberRecord> map = new HashMap<>();
users.forEach(u -> map.put(u.getAccount(),u));
activityOutcomeVo.setUserNumber(users.size());
BigDecimal amount = BigDecimal.ZERO;
List<InviteContributeVo> list = activityMapper.findInviteContributeVoList(map.keySet());
Map<String,InviteContributeVo> mapInvite = new HashMap<>();
list.forEach(m -> mapInvite.put(m.getAddress(),m));
List<InviteContributeVo> voList = new ArrayList<>();
for (String key : map.keySet()){
InviteContributeVo vo = mapInvite.get(key);
if(vo == null){
vo = new InviteContributeVo();
Integer lent = key.length();
vo.setUserName(key.substring(0,5)+"...."+key.substring(lent-5,lent));
voList.add(vo);
continue;
}
if(vo.getUserName().length() >= 20){
Integer lent = vo.getUserName().length();
vo.setUserName(vo.getUserName().substring(0,5)+"...."+vo.getUserName().substring(lent-5,lent));
}
amount = amount.add(vo.getInvitationRewards());
activityOutcomeVo.setInvitationRewards(amount);
voList.add(vo);
}
activityOutcomeVo.setInviteContributeVoList(voList);
}
}
//查询排行榜
public RankingSummaryVo ranking(BasePageReq req, UserInviteReq userInviteReq) {
RankingSummaryVo wordRanking = activityMapper.findRankingSummaryVo(userInviteReq.getAddress());
if(wordRanking == null){
wordRanking = new RankingSummaryVo();
wordRanking.setAmount("0");
}else{
TMemberRecord tMemberRecord = dslContext.select().from(T_MEMBER).where(T_MEMBER.ACCOUNT.eq(userInviteReq.getAddress())).fetchAnyInto(TMemberRecord.class);
wordRanking.setUserImg(tMemberRecord.getTwitterImg());
wordRanking.setUserName(tMemberRecord.getTwitterUserName() == null ? tMemberRecord.getAccount() : tMemberRecord.getTwitterName());
Integer lent = wordRanking.getUserName().length();
wordRanking.setUserName(lent >= 20 ? wordRanking.getUserName().substring(0,5)+"...."+wordRanking.getUserName().substring(lent-5,lent) : wordRanking.getUserName());
if(tMemberRecord.getReferId() != null && tMemberRecord.getReferId() != 0){
tMemberRecord = dslContext.select(T_MEMBER.ACCOUNT,T_MEMBER.TWITTER_USER_NAME).from(T_MEMBER).where(T_MEMBER.ID.eq(tMemberRecord.getReferId())).fetchAnyInto(TMemberRecord.class);
wordRanking.setSuperior(tMemberRecord.getTwitterName() == null ? tMemberRecord.getAccount() : tMemberRecord.getTwitterName());
lent = wordRanking.getSuperior().length();
wordRanking.setSuperior(lent >= 20 ? wordRanking.getSuperior().substring(0,5)+"...."+wordRanking.getSuperior().substring(lent-5,lent) : wordRanking.getSuperior());
}
wordRanking.setAmount(new BigDecimal(wordRanking.getAmount()).stripTrailingZeros().toPlainString());
}
List<ActivityStatisticsRecord> walletList = dslContext.selectFrom(ACTIVITY_STATISTICS)
.orderBy(ACTIVITY_STATISTICS.AMOUNT.desc(),ACTIVITY_STATISTICS.ID).limit(req.getOffset(),req.getSize())
.fetchInto(ActivityStatisticsRecord.class);
if(walletList == null || walletList.size() == 0){
return wordRanking;
}
Set<String> addressSet = new HashSet<>();
walletList.forEach(l -> {
addressSet.add(l.getAddress());
});
List<RankingVo> rankingVos = activityMapper.findRankingVoList(addressSet);
Map<String,RankingVo> map = new HashMap<>();
rankingVos.forEach(l -> map.put(l.getAddress(),l));
List<RankingVo> list = new ArrayList<>();
for (ActivityStatisticsRecord record : walletList){
RankingVo rankingVo = new RankingVo();
rankingVo.setAddress(record.getAddress());
rankingVo.setAmount(record.getAmount());
RankingVo vo = map.get(record.getAddress());
if(vo == null){
continue;
}
Integer lent = vo.getUserName().length();
rankingVo.setUserName(lent >= 20 ? vo.getUserName().substring(0,5)+"...."+vo.getUserName().substring(lent-5,lent) : vo.getUserName());
rankingVo.setUserImg(vo.getUserImg());
if(!StringUtils.isBlank(vo.getSuperior())){
lent = vo.getSuperior().length();
rankingVo.setSuperior(lent >= 20 ? vo.getSuperior().substring(0,5)+"...."+vo.getSuperior().substring(lent-5,lent) : vo.getSuperior());
}
list.add(rankingVo);
}
wordRanking.setRankingVos(list);
return wordRanking;
}
public static String generateRandomString(int length) {
Random random = new Random();
StringBuilder stringBuilder = new StringBuilder(length);
for (int i = 0; i < length; i++) {
int randomIndex = random.nextInt(CHARACTERS.length());
char randomChar = CHARACTERS.charAt(randomIndex);
stringBuilder.append(randomChar);
}
return stringBuilder.toString();
}
public void getActivityLog(String address) {
ActivityLogRecord activityLogRecord = dslContext.selectFrom(ACTIVITY_LOG).where(ACTIVITY_LOG.ADDRESS.eq(address)
.and(ACTIVITY_LOG.TYPE.eq(1)).and(ACTIVITY_LOG.CONFIG_TYPE.eq(8))).fetchAny();
if(activityLogRecord != null){
//增加用户资产统计
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(activityLogRecord.getAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(address)).execute();
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(activityLogRecord.getSuperiorAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(activityLogRecord.getSuperiorAddress())).execute();
}
}
}

View File

@ -0,0 +1,36 @@
package com.alive.server.service;
import com.alive.server.web3.ContractEventHandle;
import org.springframework.stereotype.Service;
import org.web3j.abi.EventEncoder;
import org.web3j.protocol.core.methods.response.EthLog;
import java.util.List;
@Service
public class AirTokenService implements ContractEventHandle {
final String TRANSFER_TOPIC = EventEncoder.buildEventSignature("Transfer(address,address,uint256)");
final String BUY_ROOS_SUCCESS = EventEncoder.buildEventSignature("BuyRoosSuccess(address,uint256,address,uint256,uint256,uint256[])");
final String BRIGADETOL2 = EventEncoder.buildEventSignature("BrigadeToL2(uint256,address)");
final String PAYMENTSUCCESS = EventEncoder.buildEventSignature("PaymentSuccess(address,uint256,uint256)");
@Override
public String handle(EthLog.LogObject logObject, List<String> dataList) {
if (logObject.getTopics().get(0).equalsIgnoreCase(TRANSFER_TOPIC)) {
return "Transfer";
}else if(logObject.getTopics().get(0).equalsIgnoreCase(BUY_ROOS_SUCCESS)){
return "BuyRoosSuccess";
}else if(logObject.getTopics().get(0).equalsIgnoreCase(BRIGADETOL2)){
return "BrigadeToL2";
}else if(logObject.getTopics().get(0).equalsIgnoreCase(PAYMENTSUCCESS)){
return "PaymentSuccess";
}
return null;
}
}

View File

@ -0,0 +1,55 @@
package com.alive.server.service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
/**
* 阿里快递查询
*/
@Slf4j
@Service
public class AliDeliverService {
//https://market.aliyun.com/products/57126001/cmapi023201.html
private static final String URL_FORMAT = "https://wdexpress.market.alicloudapi.com/gxali?n=";
private static final String APP_CODE = "APPCODE fc28426b30bc4cd39e139efe6cd099ca";
@Autowired
private RestTemplate restTemplate;
public JSONObject expressInfo(String expressNo, String recPhone) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
headers.add("Authorization", APP_CODE);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(headers);
String url = URL_FORMAT + expressNo;
ResponseEntity<JSONObject> responseEntity = restTemplate.exchange(url, HttpMethod.GET, requestEntity, JSONObject.class);
JSONObject jsonObject = responseEntity.getBody();
Assert.notNull(jsonObject, "暂无物流信息");
//-1单号或快递公司代码错误, 0暂无轨迹1:快递收件2在途中,3签收,4问题件 5.疑难件 6.退件签收
Integer state = jsonObject.getInteger("State");
String reason = jsonObject.getString("Reason");
Assert.isTrue(state >= 0, reason);
//倒转物流日志
JSONArray traces = jsonObject.getJSONArray("Traces");
JSONArray newTraces = new JSONArray();
int size = traces.size();
for (int i = size - 1; i >= 0; i--) {
newTraces.add(traces.get(i));
}
jsonObject.put("Traces", newTraces);
return jsonObject;
}
}

View File

@ -0,0 +1,55 @@
package com.alive.server.service;
import com.aliyun.dysmsapi20170525.Client;
import com.aliyun.dysmsapi20170525.models.SendSmsRequest;
import com.aliyun.dysmsapi20170525.models.SendSmsResponse;
import com.aliyun.tea.TeaException;
import com.aliyun.teaopenapi.models.Config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* 阿里大鱼短信
*/
@Slf4j
@Service
public class AliDySmsService {
private static final String accessKeyId = "LTAI5t8jJ56kxGVZxNf4Ph38";
private static final String accessKeySecret = "EgkRHJduyex5Ph0V9PwqhmsQsDJoGZ";
private static final String signName = "官酝和合";
private static final String templateCode = "SMS_223543777";
private static final String endPoint = "dysmsapi.aliyuncs.com";
private static final Client client;
static {
Config config = new com.aliyun.teaopenapi.models.Config()
.setAccessKeyId(accessKeyId)
.setAccessKeySecret(accessKeySecret);
config.endpoint = endPoint;
try {
client = new Client(config);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void sendSms(String mobile, String code) {
SendSmsRequest sendSmsRequest = new SendSmsRequest()
.setPhoneNumbers(mobile)
.setSignName(signName)
.setTemplateCode(templateCode)
.setTemplateParam("{\"code\":\"" + code + "\"}");
try {
SendSmsResponse response = client.sendSms(sendSmsRequest);
log.info("SendDySms {} - {}: {}", mobile, code, response.body.code);
} catch (TeaException error) {
com.aliyun.teautil.Common.assertAsString(error.message);
} catch (Exception _error) {
TeaException error = new TeaException(_error.getMessage(), _error);
com.aliyun.teautil.Common.assertAsString(error.message);
}
}
}

View File

@ -0,0 +1,268 @@
package com.alive.server.service;
import com.alive.commons.util.RedisUtil;
import com.alive.db.entity.NodeBuyLog;
import com.alive.db.entity.Vo.TransactionDataVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.methods.request.EthFilter;
import org.web3j.protocol.core.methods.response.EthLog;
import org.web3j.protocol.http.HttpService;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Slf4j
@Service
public class BscTimingService {
@Autowired
private AirTokenService airTokenService;
@Autowired
private BtcBuyService btcBuyService;
@Autowired
private NodeBuyLogService nodeBuyLogService;
@Autowired
private ChainLogService chainLogService;
@Autowired
private ActivityService activityService;
private Web3j bscWsWeb3j;
/**
* 初始化扫描
*/
private boolean initializeScan = true;
/**
* socket节点
*/
@Value("${com.alive.chainWsUrl}")
private String chainWsUrl;
/**
* 合约地址
*/
@Value("${com.alive.contractUrl}")
private String contractUrl;
public Web3j getBscWsWeb3j() {
if(bscWsWeb3j == null){
bscWsWeb3j = Web3j.build(new HttpService(chainWsUrl));
}
return bscWsWeb3j;
}
/**
* 需要同步日志的合约
* @return
*/
private List<String> getAddresses() {
return Arrays.asList(contractUrl);
}
/**
* 获取初始块任务需要注意控制时间防止链上限制调用
*/
public void printLogTask() {
String scannedBlockStr = RedisUtil.get("USDT:scannedBlock");
if (scannedBlockStr == null || scannedBlockStr.isEmpty()) {
log.error(">>> 无已扫描数据从20000块前开始");
BigInteger latestBlock = new BigInteger(RedisUtil.get("USDT:latestBlock"));
scannedBlockStr = latestBlock.subtract(BigInteger.valueOf(20000)).toString();
RedisUtil.set("USDT:scannedBlock", scannedBlockStr);
}
}
/**
* 获取最新块
*/
public void latestBlockTask() throws IOException {
BigInteger latestBlock = this.getBscWsWeb3j().ethBlockNumber().send().getBlockNumber();
RedisUtil.set("USDT:latestBlock", latestBlock.toString());
}
private List<EthLog.LogResult> scanBlock(BigInteger startBlock, BigInteger endBlock) {
EthFilter filter = new EthFilter(DefaultBlockParameter.valueOf(startBlock),
DefaultBlockParameter.valueOf(endBlock),
this.getAddresses());
EthLog send = null;
try {
send = this.getBscWsWeb3j().ethGetLogs(filter).send();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
if(send.getError() != null && send.getError().getMessage() != null){
log.info("扫描块失败(检查节点是否被限制) out {} ,{}, {}", startBlock, endBlock, send.getError().getMessage());
return null;
}
return send.getLogs();
}
/**
* 此方法频繁调用会被限制频率
* 此方法弥补订阅停止或者订阅漏掉区块补救措施
*/
public void bscScanTask() {
//获取最新块
try {
this.latestBlockTask();
this.printLogTask();
} catch (IOException e) {
}
BigInteger scannedBlock = new BigInteger(RedisUtil.get("USDT:scannedBlock"));
BigInteger latestBlock = new BigInteger(RedisUtil.get("USDT:latestBlock"));
BigInteger offset;
int times = 0;
if(initializeScan){
//项目重启扫描前60个区块
scannedBlock = scannedBlock.subtract(new BigInteger("60"));
initializeScan = false;
}
while (latestBlock.subtract(scannedBlock).longValue() > 2 && times++ < 60) {
if (latestBlock.longValue() - scannedBlock.longValue() > 10000) {
offset = BigInteger.valueOf(500);
} else if (latestBlock.longValue() - scannedBlock.longValue() > 1000) {
offset = BigInteger.valueOf(100);
} else if (latestBlock.longValue() - scannedBlock.longValue() > 100) {
offset = BigInteger.valueOf(50);
} else if (latestBlock.longValue() - scannedBlock.longValue() > 10) {
offset = BigInteger.valueOf(9);
} else if (latestBlock.longValue() - scannedBlock.longValue() > 4) {
offset = BigInteger.valueOf(3);
} else {
offset = BigInteger.valueOf(1);
}
if (latestBlock.subtract(scannedBlock).longValue() < offset.longValue()) {
break;
}
List<EthLog.LogResult> resp = this.scanBlock(scannedBlock.add(BigInteger.ONE), scannedBlock.add(offset));
if(resp == null){
return;
}
if(resp != null && resp.size() > 0){
for (EthLog.LogResult logItem : resp) {
this.handleLogEvent((EthLog.LogObject) logItem.get());
}
}
scannedBlock = scannedBlock.add(offset);
RedisUtil.set("USDT:scannedBlock", scannedBlock.toString());
}
}
private synchronized void handleLogEvent(EthLog.LogObject logObject) {
if(RedisUtil.get(logObject.getBlockHash()) != null){
//重复Hash不予处理
return;
}
//重复Hash10分钟过期
RedisUtil.setEx(logObject.getBlockHash(),"1",60 * 10);
log.info("监听到数据HASH{},块号:{},交易hash{}",logObject.getBlockHash(),logObject.getBlockNumber(),logObject.getTransactionHash());
String data = logObject.getData().substring(2);
List<String> dataList = new ArrayList<>(data.length() / 64);
//获取事件名称
String even = airTokenService.handle(logObject, dataList);
String date = logObject.getData().substring(2,logObject.getData().length());
//保存事件
chainLogService.addChainLog(logObject.getBlockHash(),logObject.getBlockNumber(),logObject.getTransactionHash(),even,date);
if(even != null && even.equals("BuyRoosSuccess")){
//我的支付地址
String address = this.getValue(date,0,true).toLowerCase();
//我的付款金额
BigDecimal amount = new BigDecimal(this.getValue(date,1,false));
//上级地址
String teamAddress = this.getValue(date,2,true).toLowerCase();
//上级奖励金额
BigDecimal teamAmount = new BigDecimal(this.getValue(date,3,false));
//订单编号
String orderNumber = this.getValue(date,4,false);
//NFT数量
String nftNUmber = this.getValue(date,6,false);
Integer number = Integer.parseInt(nftNUmber);
List<Integer> nftIds = new ArrayList<>();
for (int i = 7; i < (7 + number); i++) {
//NFT的ID
String nftId = this.getValue(date,i,false);
if(nftId == null){
break;
}
nftIds.add(Integer.parseInt(nftId));
}
NodeBuyLog log = nodeBuyLogService.findNodeSubscribeByOrderNumber(orderNumber);
if(log == null){
return;
}
log.setHash(logObject.getBlockHash());
TransactionDataVo transactionDataVo = new TransactionDataVo();
transactionDataVo.setFrom(address);
transactionDataVo.setPayAmount(amount);
transactionDataVo.setNftNumber(number);
transactionDataVo.setNftIds(nftIds);
transactionDataVo.setTeamAddress(teamAddress);
transactionDataVo.setTeamAmount(teamAmount);
transactionDataVo.setStatus(1);
btcBuyService.addNft(log,transactionDataVo);
}else if(even != null && even.equals("BrigadeToL2")){
//我的支付地址
String address = this.getValue(date,0,true).toLowerCase();
//查询用户是否有未完成的任务
activityService.getActivityLog(address);
}
}
/**
* 查询日志里面加indexed的内容
* @param topList 日志内容
* @param code 查询第几个
* @return
*/
public BigInteger getNmber(List<String> topList,Integer code){
String ret = topList.get(code);
ret = ret.substring(2,ret.length());
//16进制转10进制
return new BigInteger(ret, 16);
}
/**
* 获取没有加indexed的内容
* @param date 拆分的参数
* @param code 取的位数
* @param address 是否返回地址
* @return
*/
public String getValue(String date, Integer code, Boolean address){
int number = 64;
if(code == 0){
date = date.substring(0,number);
}else{
code = number * code;
date = date.substring(code,code+number);
}
if(date == null){
return null;
}
if(address){
return "0x"+date.substring(24,date.length());
}else{
return new BigInteger(date, 16).toString();
}
}
}

View File

@ -0,0 +1,158 @@
package com.alive.server.service;
import com.alive.commons.util.RedisUtil;
import com.alive.db.entity.NodeBuyLog;
import com.alive.db.entity.Vo.TransactionDataVo;
import io.reactivex.Flowable;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.web3j.protocol.core.methods.response.EthLog;
import org.web3j.protocol.core.methods.response.Log;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 监听同步事件
*/
@Slf4j
@Service
public class BscWsService{
@Autowired
private AirTokenService airTokenService;
@Autowired
private BtcBuyService btcBuyService;
@Autowired
private NodeBuyLogService nodeBuyLogService;
@Autowired
private ChainLogService chainLogService;
@Autowired
private ActivityService activityService;
/**
* 定义线程数,多少个线程同步socket
*/
ExecutorService executorService = Executors.newFixedThreadPool(2);
public void wsExec(Flowable<Log> flowable){
flowable.subscribe(log -> {
if(log != null){
executorService.execute(() -> handleLogEvent((EthLog.LogObject) log));
}
},throwable -> {
System.out.printf("错误-------"+ throwable.getMessage());
});
}
private synchronized void handleLogEvent(EthLog.LogObject logObject) {
if(RedisUtil.get(logObject.getBlockHash()) != null){
//重复Hash不予处理
return;
}
//重复Hash10分钟过期
RedisUtil.setEx(logObject.getBlockHash(),"1",60 * 10);
log.info("监听到数据HASH{},块号:{},交易hash{}",logObject.getBlockHash(),logObject.getBlockNumber(),logObject.getTransactionHash());
String data = logObject.getData().substring(2);
List<String> dataList = new ArrayList<>(data.length() / 64);
//获取事件名称
String even = airTokenService.handle(logObject, dataList);
String date = logObject.getData().substring(2,logObject.getData().length());
//保存事件
chainLogService.addChainLog(logObject.getBlockHash(),logObject.getBlockNumber(),logObject.getTransactionHash(),even,date);
if(even != null && even.equals("BuyRoosSuccess")){
//我的支付地址
String address = this.getValue(date,0,true).toLowerCase();
//我的付款金额
BigDecimal amount = new BigDecimal(this.getValue(date,1,false));
//上级地址
String teamAddress = this.getValue(date,2,true).toLowerCase();
//上级奖励金额
BigDecimal teamAmount = new BigDecimal(this.getValue(date,3,false));
//订单编号
String orderNumber = this.getValue(date,4,false);
//NFT数量
String nftNUmber = this.getValue(date,6,false);
Integer number = Integer.parseInt(nftNUmber);
List<Integer> nftIds = new ArrayList<>();
for (int i = 7; i < (7 + number); i++) {
//NFT的ID
String nftId = this.getValue(date,i,false);
if(nftId == null){
break;
}
nftIds.add(Integer.parseInt(nftId));
}
NodeBuyLog log = nodeBuyLogService.findNodeSubscribeByOrderNumber(orderNumber);
if(log == null){
return;
}
log.setHash(logObject.getBlockHash());
TransactionDataVo transactionDataVo = new TransactionDataVo();
transactionDataVo.setFrom(address);
transactionDataVo.setPayAmount(amount);
transactionDataVo.setNftNumber(number);
transactionDataVo.setNftIds(nftIds);
transactionDataVo.setTeamAddress(teamAddress);
transactionDataVo.setTeamAmount(teamAmount);
transactionDataVo.setStatus(1);
btcBuyService.addNft(log,transactionDataVo);
}else if(even != null && even.equals("BrigadeToL2")){
//我的支付地址
String address = this.getValue(date,0,true).toLowerCase();
//查询用户是否有未完成的任务
activityService.getActivityLog(address);
}
}
/**
* 查询日志里面加indexed的内容
* @param topList 日志内容
* @param code 查询第几个
* @return
*/
public BigInteger getNmber(List<String> topList,Integer code){
String ret = topList.get(code);
ret = ret.substring(2,ret.length());
//16进制转10进制
return new BigInteger(ret, 16);
}
/**
* 获取没有加indexed的内容
* @param date 拆分的参数
* @param code 取的位数
* @param address 是否返回地址
* @return
*/
public String getValue(String date, Integer code, Boolean address){
int number = 64;
if(code == 0){
date = date.substring(0,number);
}else{
code = number * code;
date = date.substring(code,code+number);
}
if(date == null){
return null;
}
if(address){
return "0x"+date.substring(24,date.length());
}else{
return new BigInteger(date, 16).toString();
}
}
}

View File

@ -0,0 +1,231 @@
package com.alive.server.service;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alive.commons.config.BaseComponent;
import com.alive.commons.util.DateUtils;
import com.alive.commons.util.HttpUtils;
import com.alive.commons.util.RedisUtil;
import com.alive.db.entity.NodeBuyLog;
import com.alive.db.entity.Vo.TransactionDataVo;
import com.alive.db.jooq.tables.records.NodeRecord;
import com.alive.db.mapper.NodeSettingMapper;
import com.alive.server.web3.Web3jServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.List;
import static com.alive.db.jooq.Tables.NODE;
/**
*
* @author HayDen
* @date 2024-01-09
*/
@Slf4j
@Service
public class BtcBuyService extends BaseComponent
{
@Autowired
private NodeBuyLogService nodeBuyLogService;
@Autowired
private NodeNftConfigService nodeNftConfigService;
@Resource
private NodeSettingMapper nodeSettingMapper;
@Autowired
private Web3jServer web3jServer;
/**
* 检查是否支付成功
*/
public void exec() {
List<NodeBuyLog> nodeSubscribes = nodeBuyLogService.selectNodeSubscribeList(new NodeBuyLog().setStatus(1));
if(nodeSubscribes != null && nodeSubscribes.size() > 0){
for (NodeBuyLog nodeSubscribe : nodeSubscribes){
if(DateUtils.addMinute(nodeSubscribe.getCreateTime(),30).getTime() < System.currentTimeMillis()){
nodeSubscribe.setStatus(4);
nodeSubscribe.setIllustrate("订单创建超过30分钟未支付");
nodeBuyLogService.updateOrAddNodeSubscribe(nodeSubscribe);
}
}
}
nodeSubscribes = nodeBuyLogService.selectNodeSubscribeList(new NodeBuyLog().setStatus(2));
for (NodeBuyLog nodeSubscribe : nodeSubscribes){
log.info("开始确认链上用户购买情况,订单ID{}---------------------------------",nodeSubscribe.getId());
//通过hash查询链上数据
TransactionDataVo transactionDataVo = null;
try {
transactionDataVo = web3jServer.getEthLogsByHash(nodeSubscribe.getHash());
} catch (IOException e) {
RedisUtil.setEx(nodeSubscribe.getHash(),"0",30);
nodeSubscribe.setIllustrate("订单hash数据异常");
nodeSubscribe.setStatus(4);
nodeBuyLogService.updateOrAddNodeSubscribe(nodeSubscribe);
log.info("订单确认失败:{}---------------------------------",nodeSubscribe.getId());
continue;
}
if(transactionDataVo == null){
continue;
}
this.addNft(nodeSubscribe,transactionDataVo);
}
}
/**
* 铸造NFT
* @param nodeSubscribe 订单信息
* @param transactionDataVo 铸造链上信息
*/
public void addNft(NodeBuyLog nodeSubscribe,TransactionDataVo transactionDataVo){
//订单与链上数据对比
this.dataVerify(nodeSubscribe,transactionDataVo);
log.info("本次订单数据确认结果是:{}---------------------------------",nodeSubscribe.getStatus());
String nftIds = "";
if(nodeSubscribe.getStatus() == 3){
for (Integer nftId : transactionDataVo.getNftIds()){
nftIds += "#"+nftId+" ";
//支付成功
NodeRecord nodeRecord = dslContext.newRecord(NODE);
nodeRecord.setId(nftId);
nodeRecord.setNodeSettingId(nodeSubscribe.getNodeSettingId());
nodeRecord.setBuyCoin(nodeSubscribe.getPayCoin());
nodeRecord.setBuyAmount(nodeSubscribe.getBuyAmount().divide(new BigDecimal(nodeSubscribe.getBuyCount()),4,BigDecimal.ROUND_HALF_UP));
nodeRecord.setBuyNumber(1);
nodeRecord.setNodeName(nodeSubscribe.getNodeName());
nodeRecord.setConfirmTime(new Timestamp(System.currentTimeMillis()));
nodeRecord.setUserId(nodeSubscribe.getUserId());
nodeRecord.setOrderNumber(nodeSubscribe.getOrderNumber());
nodeRecord.store();
}
//开始给上级发放奖励
nodeNftConfigService.reward(nodeSubscribe);
//减少库存
nodeSettingMapper.addInventory(nodeSubscribe.getBuyCount(),nodeSubscribe.getNodeSettingId(),nodeSubscribe.getBuyAmount());
}
if(nodeSubscribe.getStatus() != 2){
nodeBuyLogService.updateOrAddNodeSubscribe(nodeSubscribe);
}
//订单超过2小时无法确认直接失败处理
if(nodeSubscribe.getStatus() == 2 && DateUtils.addMinute(nodeSubscribe.getCreateTime(),30).getTime() < System.currentTimeMillis()){
nodeSubscribe.setStatus(4);
nodeSubscribe.setIllustrate("订单链上确认超过30分钟直接取消");
nodeBuyLogService.updateOrAddNodeSubscribe(nodeSubscribe);
}
if(nodeSubscribe.getStatus().equals(4) || nodeSubscribe.getStatus().equals(3)){
RedisUtil.setEx(nodeSubscribe.getHash(),nodeSubscribe.getStatus().equals(4) ? "0" : nftIds,30);
}
}
/**
* 开始对比链上数据是否正确
* @param nodeSubscribe
* @param transactionDataVo
*/
public void dataVerify(NodeBuyLog nodeSubscribe,TransactionDataVo transactionDataVo){
BigDecimal limit = new BigDecimal("1000000");
transactionDataVo.setTeamAmount(transactionDataVo.getTeamAmount().divide(limit));
transactionDataVo.setPayAmount(transactionDataVo.getPayAmount().divide(limit));
String address0x = "0x0000000000000000000000000000000000000000";
if(transactionDataVo.getTeamAddress().equals(address0x)){
transactionDataVo.setTeamAddress("0");
}
if(transactionDataVo.getStatus() == null || transactionDataVo.getStatus().equals(-1)){
//链上确认中
return;
}
if(transactionDataVo.getStatus().equals(0)){
nodeSubscribe.setIllustrate("链上失败");
nodeSubscribe.setStatus(4);
return;
}
if(!nodeSubscribe.getTeamAddress().equals("0") && nodeSubscribe.getRebate().compareTo(BigDecimal.ZERO) != 0){
if(!transactionDataVo.getTeamAddress().equals("0") && nodeSubscribe.getRebate().compareTo(transactionDataVo.getTeamAmount()) != 0){
nodeSubscribe.setIllustrate("上级奖励金额不一致");
nodeSubscribe.setStatus(4);
return;
}
if(nodeSubscribe.getTeamAddress().compareTo(transactionDataVo.getTeamAddress()) != 0){
nodeSubscribe.setIllustrate("上级地址奖励不一致");
nodeSubscribe.setStatus(4);
return;
}
}
if(transactionDataVo.getPayAmount().compareTo(nodeSubscribe.getBuyAmount()) != 0){
nodeSubscribe.setIllustrate("支付金额不一致");
nodeSubscribe.setStatus(4);
return;
}
if(!transactionDataVo.getFrom().equals(nodeSubscribe.getWalletAddress())){
nodeSubscribe.setIllustrate("支付地址不一致");
nodeSubscribe.setStatus(4);
}
if(!transactionDataVo.getNftNumber().equals(nodeSubscribe.getBuyCount())){
nodeSubscribe.setIllustrate("NFT铸造数量不一致");
nodeSubscribe.setStatus(4);
}else{
nodeSubscribe.setIllustrate("铸造成功");
nodeSubscribe.setStatus(3);
}
}
public Boolean httpContractByHash(NodeBuyLog nodeSubscribe,BigDecimal scope,String configAddress){
if(nodeSubscribe.getHash() == null){
nodeSubscribe.setStatus(4);
}else{
String hash = nodeSubscribe.getHash();
String value = HttpUtils.sendGet("https://blockchain.info/rawtx/"+hash);
if(StringUtils.isBlank(value)){
return true;
}
JSONObject qu = JSONObject.parseObject(value, JSONObject.class);
//获取到交易数据
if(qu.get("block_index") == null || qu.get("block_height") == null){
//区块未确认
return false;
}
//交易发起数据
JSONArray inputs = qu.getJSONArray("inputs");
JSONObject inputsValue = inputs.getJSONObject(0).getJSONObject("prev_out");
{
//出账地址
String address = inputsValue.get("addr").toString().toLowerCase();
nodeSubscribe.setInputAddress(address);
nodeSubscribe.setStatus(3);
}
{
JSONArray out = qu.getJSONArray("out");
JSONObject outUser = out.getJSONObject(0);
//收款地址
String address = outUser.get("addr").toString().toLowerCase();
//出账金额
String inpAmount = outUser.get("value").toString();
//放大计算
if(new BigDecimal(inpAmount).compareTo(nodeSubscribe.getBuyAmount().multiply(scope)) != 0){
nodeSubscribe.setStatus(4);
}
nodeSubscribe.setOutAddress(address);
if(!configAddress.equals(address)){
//收款地址不对
nodeSubscribe.setStatus(4);
}
//收款金额
//String outAmount = outUser.get("value").toString();
//手续费
//JSONObject outUserFee = out.getJSONObject(1);
//String fee = outUserFee.get("value").toString();
}
}
return true;
}
}

View File

@ -0,0 +1,29 @@
package com.alive.server.service;
import com.alive.db.jooq.tables.records.ChainLogRecord;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigInteger;
import static com.alive.db.jooq.Tables.CHAIN_LOG;
@Service
public class ChainLogService
{
@Autowired
private DSLContext dslContext;
public void addChainLog(String hash, BigInteger blockNumber,String transactionHash, String even, String date)
{
ChainLogRecord chainLogRecord = dslContext.newRecord(CHAIN_LOG);
chainLogRecord.setHash(hash);
chainLogRecord.setBlockNumber(blockNumber.toString());
chainLogRecord.setChainName(even);
chainLogRecord.setDataValue(date);
chainLogRecord.setTransactionHash(transactionHash);
chainLogRecord.store();
}
}

View File

@ -0,0 +1,71 @@
package com.alive.server.service;
import com.alive.commons.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
@Slf4j
@Service
public class CodeService {
@Autowired
private DingService dingService;
@Autowired
private AliDySmsService aliDySmsService;
@Value("${spring.profiles.active}")
private String env;
private final static String PRE_FIX_FORMAT = "juxing:chapter:%d:%s";
private final static long EXPIRE_TIME = 600;
private final static int TYPE = 0;
public void send(String mobile, int type) {
String code = RedisUtil.get(String.format(PRE_FIX_FORMAT, TYPE, mobile));
long ttl = -1;
if (code != null) {
ttl = RedisUtil.ttl(String.format(PRE_FIX_FORMAT, TYPE, mobile));
Assert.isTrue(ttl < 500, "发送过于频繁");
}
if (ttl < 200) {
//如果验证码小于200s过期更换验证码
code = RandomStringUtils.random(6, false, true);
}
RedisUtil.setEx(String.format(PRE_FIX_FORMAT, TYPE, mobile), code, EXPIRE_TIME);
log.info("发送验证码:{} - {}", mobile, code);
if ("prod".equals(env)) {
aliDySmsService.sendSms(mobile, code);
return;
}
String content = "【官酝和合】您的验证码是" + code + "。如非本人操作,请忽略本短信";
//dingService.sendMsg(mobile, content);
}
public boolean check(String mobile, int type, String code) {
String saved = RedisUtil.get(String.format(PRE_FIX_FORMAT, TYPE, mobile));
if (saved == null || code == null) {
return false;
}
if ("000000".equals(code) && !env.equals("prod")) {
return true;
}
return code.equals(saved);
}
public boolean checkAndDel(String mobile, int type, String code) {
if (!check(mobile, TYPE, code)) {
return false;
}
del(mobile);
return true;
}
public void del(String mobile) {
RedisUtil.del(String.format(PRE_FIX_FORMAT, TYPE, mobile));
}
}

View File

@ -0,0 +1,464 @@
package com.alive.server.service;
import com.alive.commons.config.BaseComponent;
import com.alive.commons.enums.WalletLogTypeEnum;
import com.alive.commons.model.BasePageReq;
import com.alive.commons.util.*;
import com.alive.db.entity.NodeBuyLog;
import com.alive.db.entity.Vo.*;
import com.alive.db.jooq.tables.pojos.SysConfigPojo;
import com.alive.db.jooq.tables.records.*;
import com.alive.db.mapper.NodeSettingMapper;
import com.alive.db.mapper.PersonalCenterMapper;
import com.alive.server.api.account.PayCoinReq;
import com.alive.server.api.account.PayNodeSmsReq;
import com.alive.server.api.account.TeskReq;
import com.alive.server.dto.WalletOperation;
import com.alive.server.web3.Web3jServer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.annotation.OrderUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.web3j.abi.datatypes.Int;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameter;
import org.web3j.protocol.core.methods.request.EthFilter;
import org.web3j.protocol.core.methods.response.EthLog;
import org.web3j.protocol.http.HttpService;
import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Member;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.*;
import static com.alive.db.jooq.Tables.*;
@Slf4j
@Service
public class CrowdfundingService extends BaseComponent {
@Autowired
private MemberService memberService;
@Autowired
private WalletService walletService;
@Autowired
private ChainLogService chainLogService;
@Autowired
private AirTokenService airTokenService;
/**
* 合约地址
*/
@Value("${com.alive.contractUrl}")
private String contractUrl;
/**
* 初始化扫描
*/
private boolean initializeScan = true;
@Autowired
private Web3jServer web3jServer;
public Web3j getBscWsWeb3j() {
return web3jServer.getWeb3j();
}
/**
* 需要同步日志的合约
* @return
*/
private List<String> getAddresses() {
return Arrays.asList(contractUrl);
}
public Boolean payNodeSms(PayNodeSmsReq req) {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
PayCoinLogRecord payCoinLogRecord = dslContext.select().from(PAY_COIN_LOG).where(PAY_COIN_LOG.STATUS.eq(1))
.and(PAY_COIN_LOG.MEMBER_ID.eq(memberId)).and(PAY_COIN_LOG.ORDER_NUMBER.eq(req.getOrderNumber())).fetchAnyInto(PayCoinLogRecord.class);
Assert.isTrue(payCoinLogRecord != null && payCoinLogRecord.getStatus().equals(1), "Order error");
if (req.getStatus().equals(2)) {
dslContext.update(PAY_COIN_LOG).set(PAY_COIN_LOG.STATUS,4).set(PAY_COIN_LOG.ILLUSTRATE,"取消订单")
.where(PAY_COIN_LOG.ID.eq(payCoinLogRecord.getId())).execute();
return true;
}
dslContext.update(PAY_COIN_LOG).set(PAY_COIN_LOG.HASH,req.getHash())
.where(PAY_COIN_LOG.ID.eq(payCoinLogRecord.getId())).execute();
return true;
}
public PrivatePlacementVo getPrivatePlacement() {
PrivatePlacementVo privatePlacementVo = new PrivatePlacementVo();
List<CoinConfigRecord> coins = dslContext.select().from(COIN_CONFIG).where(COIN_CONFIG.STATE.eq(1)).fetchInto(CoinConfigRecord.class);
if(coins != null && coins.size() > 0){
CoinConfigRecord coin = coins.get(0);
privatePlacementVo.setUsdtPrice(coin.getUsdtPrice().stripTrailingZeros().toPlainString());
privatePlacementVo.setMinNumber(coin.getMinNumber().stripTrailingZeros().toPlainString());
privatePlacementVo.setPrivatePlacement(coin.getPrivatePlacement().stripTrailingZeros().toPlainString());
privatePlacementVo.setToPrivatePlacement(coin.getToPrivatePlacement().stripTrailingZeros().toPlainString());
privatePlacementVo.setCoinId(coin.getId());
}
if(StringUtils.isBlank(RequestUtil.getToken())){
privatePlacementVo.setWordPrivatePlacement("0");
privatePlacementVo.setWordAirdrop("0");
return privatePlacementVo;
}
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
List<TMemberWalletRecord> walletRecords = dslContext.select().from(T_MEMBER_WALLET).where(T_MEMBER_WALLET.MEMBER_ID.eq(memberId)).fetchInto(TMemberWalletRecord.class);
for (TMemberWalletRecord memberWalletRecord : walletRecords){
if(memberWalletRecord.getCoinId().equals(1)){
privatePlacementVo.setWordPrivatePlacement(memberWalletRecord.getBalance().add(memberWalletRecord.getFrozen()).stripTrailingZeros().toPlainString());
}else if(memberWalletRecord.getCoinId().equals(2)){
privatePlacementVo.setWordAirdrop(memberWalletRecord.getBalance().add(memberWalletRecord.getFrozen()).stripTrailingZeros().toPlainString());
}
}
return privatePlacementVo;
}
/**
* 用户下单
* @param req
* @return
*/
public PayCoinVo payOrder(PayCoinReq req) {
BigDecimal amount = new BigDecimal(req.getAmount());
CoinConfigRecord configRecord = dslContext.select().from(COIN_CONFIG).where(COIN_CONFIG.ID.eq(req.getCoinId())).fetchAnyInto(CoinConfigRecord.class);
Assert.isTrue(configRecord != null, "Coin config is null");
Assert.isTrue(amount.compareTo(configRecord.getMinNumber()) >= 0 && amount.compareTo(configRecord.getMaxNumber()) <= 0, "Minimum or maximum purchase quantity limits");
Assert.isTrue(configRecord.getPrivatePlacement().subtract(configRecord.getToPrivatePlacement()).subtract(amount).compareTo(BigDecimal.ZERO) >= 0, "Insufficient inventory");
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
TMemberRecord tMemberRecord = memberService.fetchOne(memberId);
PayCoinLogRecord payCoinLogRecord = dslContext.newRecord(PAY_COIN_LOG);
payCoinLogRecord.setMemberId(tMemberRecord.getId());
payCoinLogRecord.setAddress(tMemberRecord.getAccount());
payCoinLogRecord.setCoinName(configRecord.getCoinName());
payCoinLogRecord.setUnitPrice(configRecord.getUsdtPrice());
payCoinLogRecord.setAmount(amount);
payCoinLogRecord.setPayUsdt(amount.multiply(configRecord.getUsdtPrice()));
payCoinLogRecord.setStatus(1);
payCoinLogRecord.setOrderNumber(NumberUtil.getUUIDBy16());
payCoinLogRecord.setCoinId(configRecord.getId());
payCoinLogRecord.setCoinName(configRecord.getCoinName());
payCoinLogRecord.store();
PayCoinVo payCoinVo = new PayCoinVo();
payCoinVo.setOrderNumber(payCoinLogRecord.getOrderNumber());
payCoinVo.setUsdtAmount(payCoinLogRecord.getPayUsdt().multiply(new BigDecimal("1000000000000000000")));
return payCoinVo;
}
/**
* 众筹确认是否支付成功
*/
public void exec() {
List<PayCoinLogRecord> payCoinLogRecords = dslContext.select().from(PAY_COIN_LOG).where(PAY_COIN_LOG.STATUS.eq(1)).fetchInto(PayCoinLogRecord.class);
List<PayCoinLogRecord> payCoinLogRecordList = new ArrayList<>();
if(payCoinLogRecords != null && payCoinLogRecords.size() > 0){
for (PayCoinLogRecord nodeSubscribe : payCoinLogRecords){
if(DateUtils.addMinute(nodeSubscribe.getCreateTime(),30).getTime() < System.currentTimeMillis()){
dslContext.update(PAY_COIN_LOG).set(PAY_COIN_LOG.STATUS,4).set(PAY_COIN_LOG.ILLUSTRATE,"订单创建超过30分钟未支付")
.where(PAY_COIN_LOG.ID.eq(nodeSubscribe.getId())).execute();
continue;
}
payCoinLogRecordList.add(nodeSubscribe);
}
}
for (PayCoinLogRecord payCoinLogRecord : payCoinLogRecordList){
if(payCoinLogRecord.getHash() == null){
continue;
}
log.info("开始确认链上用户购买情况,订单ID{}---------------------------------",payCoinLogRecord.getId());
//通过hash查询链上数据
PayCoinVo payCoinVo = null;
try {
payCoinVo = web3jServer.crowdfundingByHash(payCoinLogRecord.getHash());
} catch (IOException e) {
RedisUtil.setEx(payCoinLogRecord.getHash(),"0",30);
dslContext.update(PAY_COIN_LOG).set(PAY_COIN_LOG.STATUS,4).set(PAY_COIN_LOG.ILLUSTRATE,"订单hash数据异常")
.where(PAY_COIN_LOG.ID.eq(payCoinLogRecord.getId())).execute();
log.info("订单确认失败:{}---------------------------------",payCoinLogRecord.getId());
continue;
}
if(payCoinVo == null){
continue;
}
this.addPrivatePlacement(payCoinLogRecord,payCoinVo);
}
}
/**
* 私募
* @param nodeSubscribe 订单信息
* @param transactionDataVo 铸造链上信息
*/
public void addPrivatePlacement(PayCoinLogRecord nodeSubscribe,PayCoinVo transactionDataVo){
//订单与链上数据对比
this.dataVerify(nodeSubscribe,transactionDataVo);
log.info("本次订单数据确认结果是:{}---------------------------------",nodeSubscribe.getStatus());
String nftIds = "";
if(nodeSubscribe.getStatus() == 3){
//入账
TMemberWalletRecord walletRecord= walletService.getWallet(nodeSubscribe.getMemberId(), nodeSubscribe.getCoinId());
WalletOperation walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.PRIVATE_PLACEMENT,nodeSubscribe.getAmount(),"私募");
walletService.operateBalance(walletOperation);
//减少库存
dslContext.update(COIN_CONFIG).set(COIN_CONFIG.TO_PRIVATE_PLACEMENT,COIN_CONFIG.TO_PRIVATE_PLACEMENT.add(nodeSubscribe.getAmount()))
.where(COIN_CONFIG.ID.eq(nodeSubscribe.getCoinId())).execute();
}
if(nodeSubscribe.getStatus() != 2){
dslContext.update(PAY_COIN_LOG).set(PAY_COIN_LOG.STATUS,nodeSubscribe.getStatus()).set(PAY_COIN_LOG.ILLUSTRATE,nodeSubscribe.getIllustrate())
.where(PAY_COIN_LOG.ID.eq(nodeSubscribe.getId())).execute();
}
//订单超过2小时无法确认直接失败处理
if(nodeSubscribe.getStatus() == 2 && DateUtils.addMinute(nodeSubscribe.getCreateTime(),30).getTime() < System.currentTimeMillis()){
dslContext.update(PAY_COIN_LOG).set(PAY_COIN_LOG.STATUS,4).set(PAY_COIN_LOG.ILLUSTRATE,"订单链上确认超过30分钟直接取消")
.where(PAY_COIN_LOG.ID.eq(nodeSubscribe.getId())).execute();
}
if(nodeSubscribe.getStatus().equals(4) || nodeSubscribe.getStatus().equals(3)){
RedisUtil.setEx(nodeSubscribe.getHash(),nodeSubscribe.getStatus().equals(4) ? "0" : nftIds,30);
}
}
/**
* 开始对比链上数据是否正确
* @param nodeSubscribe
* @param transactionDataVo
*/
public void dataVerify(PayCoinLogRecord nodeSubscribe,PayCoinVo transactionDataVo){
BigDecimal limit = new BigDecimal("1000000000000000000");
transactionDataVo.setUsdtAmount(transactionDataVo.getUsdtAmount().divide(limit));
if(transactionDataVo.getStatus() == null || transactionDataVo.getStatus().equals(-1)){
//链上确认中
return;
}
if(transactionDataVo.getStatus().equals(0)){
nodeSubscribe.setIllustrate("链上失败");
nodeSubscribe.setStatus(4);
return;
}
if(transactionDataVo.getUsdtAmount().compareTo(nodeSubscribe.getPayUsdt()) != 0){
nodeSubscribe.setIllustrate("支付金额不一致");
nodeSubscribe.setStatus(4);
return;
}
if(!transactionDataVo.getAddress().equals(nodeSubscribe.getAddress())){
nodeSubscribe.setIllustrate("支付地址不一致");
nodeSubscribe.setStatus(4);
}
nodeSubscribe.setIllustrate("成功");
nodeSubscribe.setStatus(3);
}
/**
* 获取初始块任务需要注意控制时间防止链上限制调用
*/
public void printLogTask() {
String scannedBlockStr = RedisUtil.get("ALIVE-USDT:scannedBlock");
if (scannedBlockStr == null || scannedBlockStr.isEmpty()) {
log.error(">>> 无已扫描数据从20000块前开始");
BigInteger latestBlock = new BigInteger(RedisUtil.get("ALIVE-USDT:latestBlock"));
scannedBlockStr = latestBlock.subtract(BigInteger.valueOf(20000)).toString();
RedisUtil.set("ALIVE-USDT:scannedBlock", scannedBlockStr);
}
}
/**
* 获取最新块
*/
public void latestBlockTask() throws IOException {
BigInteger latestBlock = this.getBscWsWeb3j().ethBlockNumber().send().getBlockNumber();
RedisUtil.set("ALIVE-USDT:latestBlock", latestBlock.toString());
}
private synchronized List<EthLog.LogResult> scanBlock(BigInteger startBlock, BigInteger endBlock) {
EthFilter filter = new EthFilter(DefaultBlockParameter.valueOf(startBlock),
DefaultBlockParameter.valueOf(endBlock),
this.getAddresses());
EthLog send = null;
try {
send = this.getBscWsWeb3j().ethGetLogs(filter).send();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
if(send.getError() != null && send.getError().getMessage() != null){
log.info("扫描块失败(检查节点是否被限制) out {} ,{}, {}", startBlock, endBlock, send.getError().getMessage());
return null;
}
return send.getLogs();
}
/**
* 此方法频繁调用会被限制频率
* 此方法弥补订阅停止或者订阅漏掉区块补救措施
*/
public void bscScanTask() {
//获取最新块
try {
this.latestBlockTask();
this.printLogTask();
} catch (IOException e) {
}
BigInteger scannedBlock = new BigInteger(RedisUtil.get("ALIVE-USDT:scannedBlock"));
BigInteger latestBlock = new BigInteger(RedisUtil.get("ALIVE-USDT:latestBlock"));
log.info("=====:{},%%%%%%:{}",scannedBlock,latestBlock);
BigInteger offset;
int times = 0;
if(initializeScan){
//项目重启扫描前60个区块
scannedBlock = scannedBlock.subtract(new BigInteger("60"));
initializeScan = false;
}
while (latestBlock.subtract(scannedBlock).longValue() > 2 && times++ < 60) {
if (latestBlock.longValue() - scannedBlock.longValue() > 10000) {
offset = BigInteger.valueOf(500);
} else if (latestBlock.longValue() - scannedBlock.longValue() > 1000) {
offset = BigInteger.valueOf(100);
} else if (latestBlock.longValue() - scannedBlock.longValue() > 100) {
offset = BigInteger.valueOf(50);
} else if (latestBlock.longValue() - scannedBlock.longValue() > 10) {
offset = BigInteger.valueOf(9);
} else if (latestBlock.longValue() - scannedBlock.longValue() > 4) {
offset = BigInteger.valueOf(3);
} else {
offset = BigInteger.valueOf(1);
}
if (latestBlock.subtract(scannedBlock).longValue() < offset.longValue()) {
break;
}
List<EthLog.LogResult> resp = this.scanBlock(scannedBlock.add(BigInteger.ONE), scannedBlock.add(offset));
if(resp == null){
return;
}
if(resp != null && resp.size() > 0){
for (EthLog.LogResult logItem : resp) {
this.handleLogEvent((EthLog.LogObject) logItem.get());
}
}
scannedBlock = scannedBlock.add(offset);
RedisUtil.set("ALIVE-USDT:scannedBlock", scannedBlock.toString());
}
}
private synchronized void handleLogEvent(EthLog.LogObject logObject) {
if(RedisUtil.get(logObject.getBlockHash()) != null){
//重复Hash不予处理
return;
}
//重复Hash10分钟过期
RedisUtil.setEx(logObject.getBlockHash(),"1",60 * 10);
log.info("监听到数据HASH{},块号:{},交易hash{}",logObject.getBlockHash(),logObject.getBlockNumber(),logObject.getTransactionHash());
String data = logObject.getData().substring(2);
List<String> dataList = new ArrayList<>(data.length() / 64);
//获取事件名称
String even = airTokenService.handle(logObject, dataList);
String date = logObject.getData().substring(2,logObject.getData().length());
//保存事件
chainLogService.addChainLog(logObject.getBlockHash(),logObject.getBlockNumber(),logObject.getTransactionHash(),even,date);
if(even != null && even.equals("PaymentSuccess")){
//我的支付地址
String address = this.getValue(date,0,true).toLowerCase();
//我的付款金额
BigDecimal amount = new BigDecimal(this.getValue(date,1,false));
//上级地址
String orderNumber = this.getValue(date,2,false);
PayCoinLogRecord payCoinLogRecord = dslContext.select().from(PAY_COIN_LOG).where(PAY_COIN_LOG.ORDER_NUMBER.eq(orderNumber)).fetchAnyInto(PayCoinLogRecord.class);
if(payCoinLogRecord == null){
return;
}
payCoinLogRecord.setHash(logObject.getBlockHash());
PayCoinVo payCoinVo = new PayCoinVo();
payCoinVo.setAddress(address);
payCoinVo.setUsdtAmount(amount);
payCoinVo.setOrderNumber(orderNumber);
payCoinVo.setStatus(1);
this.addPrivatePlacement(payCoinLogRecord,payCoinVo);
}
}
/**
* 查询日志里面加indexed的内容
* @param topList 日志内容
* @param code 查询第几个
* @return
*/
public BigInteger getNmber(List<String> topList,Integer code){
String ret = topList.get(code);
ret = ret.substring(2,ret.length());
//16进制转10进制
return new BigInteger(ret, 16);
}
/**
* 获取没有加indexed的内容
* @param date 拆分的参数
* @param code 取的位数
* @param address 是否返回地址
* @return
*/
public String getValue(String date, Integer code, Boolean address){
int number = 64;
if(code == 0){
date = date.substring(0,number);
}else{
code = number * code;
date = date.substring(code,code+number);
}
if(date == null){
return null;
}
if(address){
return "0x"+date.substring(24,date.length());
}else{
return new BigInteger(date, 16).toString();
}
}
public String contractAddress() {
SysConfigPojo config = dslContext.select().from(SYS_CONFIG).where(SYS_CONFIG.CONFIG_KEY.eq("PRIVATE_PLACEMENT")).fetchAnyInto(SysConfigPojo.class);
return config.getValue();
}
/**
* 领取空投
* @return
*/
public Map<String, String> claimTheAirdrop() {
Map<String, String> map = new HashMap<>();
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
CoinConfigRecord configRecord = dslContext.select().from(COIN_CONFIG).where(COIN_CONFIG.AIRDROP_NUMBER.gt(BigDecimal.ZERO)).limit(1).fetchAnyInto(CoinConfigRecord.class);
Assert.isTrue(configRecord != null, "Claim failed");
Integer count = dslContext.selectCount().from(T_MEMBER_WALLET_LOG).where(T_MEMBER_WALLET_LOG.COIN_ID.eq(configRecord.getId())
.and(T_MEMBER_WALLET_LOG.MEMBER_ID.eq(memberId)).and(T_MEMBER_WALLET_LOG.OP_TYPE.eq(WalletLogTypeEnum.AIRDROP.getCode()))).fetchAnyInto(Integer.class);
Assert.isTrue(count <= 0, "You ve already claimed it");
TMemberWalletRecord walletRecord = dslContext.select().from(T_MEMBER_WALLET).where(T_MEMBER_WALLET.COIN_ID.eq(configRecord.getId())
.and(T_MEMBER_WALLET.MEMBER_ID.eq(memberId))).fetchAnyInto(TMemberWalletRecord.class);
WalletOperation walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.AIRDROP,configRecord.getAirdropNumber(),"空投");
walletService.operateBalance(walletOperation);
map.put("result","true");
return map;
}
public String getAirdropNumber() {
CoinConfigRecord configRecord = dslContext.select().from(COIN_CONFIG).where(COIN_CONFIG.AIRDROP_NUMBER.gt(BigDecimal.ZERO)).limit(1).fetchAnyInto(CoinConfigRecord.class);
if(configRecord == null){
return "0";
}
return configRecord.getAirdropNumber().stripTrailingZeros().toPlainString();
}
}

View File

@ -0,0 +1,82 @@
package com.alive.server.service;
import com.alive.commons.util.ShaUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Map;
@Slf4j
@Service
//@Profile({"dev", "test"})
public class DingService {
@Autowired
private RestTemplate restTemplate;
private final String token = "92c6649e0ab689bf8963fc6102a49b038832aa16ed85e58627c56355434b02d9";
private final String secret = "SEC941a9e16fc8f5eb20ad9786f84c8226d8831bd9b61d69a06ad8d216a67bb2043";
//https://oapi.dingtalk.com/robot/send?access_token=a16e52a33b63efd8cebfc718680dd916047b29fddc076b8a27496c573e976abf
public void sendMsg(String mobile, String content) {
long timestamp = System.currentTimeMillis();
String sign = null;
try {
byte[] signData = ShaUtil.hmacSha256(timestamp + "\n" + secret, secret);
sign = URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
String sendUrl = String.format("https://oapi.dingtalk.com/robot/send?access_token=%s&timestamp=%s&sign=%s", token, timestamp, sign);
String msg = String.format("[测试信息] \n\n发往%s\n\n内容 %s", mobile, content);
//log.info("测试信息:{}", msg);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<DingTalkMsgDTO> request = new HttpEntity<>(new DingTalkMsgDTO(msg), headers);
Map resp = restTemplate.postForObject(sendUrl, request, Map.class);
System.out.println(resp);
}
@Data
private static class DingTalkMsgDTO {
//消息格式写死文本
private final String msgtype = "markdown";
private Markdown markdown;
public DingTalkMsgDTO(String mdText) {
markdown = new Markdown();
markdown.setTitle("测试短信");
markdown.setText(mdText);
}
// private Text text;
// public DingTalkMsgDTO(String msg) {
// text = new Text();
// text.content = msg;
// }
@Data
public static class Text {
private String content;
}
@Data
public static class Markdown {
private String title;
private String text;
}
}
}

View File

@ -0,0 +1,331 @@
package com.alive.server.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alive.server.config.DiscordConfig;
import com.alive.server.dto.DiscordlaborUnionDto;
import com.alive.server.dto.UserDto;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import static com.alive.db.jooq.Tables.T_MEMBER;
@Slf4j
@Service
public class DiscordService {
@Autowired
private DSLContext dslContext;
/**
* 生成授权链接
* @return
*/
public String getAuthorizationUrl(String address) {
Map<String,String> map = new HashMap<>();
String url = "https://discord.com/oauth2/authorize?";
url += "client_id="+ DiscordConfig.CLIENT_ID;
//访问权限
url += "&response_type=code";
//回调地址
url += "&redirect_uri="+DiscordConfig.TOKEN_URL;
//用户地址
url += "&state="+address;
url += "&scope=identify+guilds+gdm.join+guilds.join+guilds.members.read";
return url;
}
/**
* 获取用户token
* @param code
* @param address
*/
public String getTokenByCode(String code,String address){
try {
String clientId = URLEncoder.encode(DiscordConfig.CLIENT_ID, "UTF-8");
String clientSecret = URLEncoder.encode(DiscordConfig.CLIENT_SECRET, "UTF-8");
String credentials = clientId + ":" + clientSecret;
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
OkHttpClient client = new OkHttpClient();
String requestBody = null;
String refreshToken = DiscordConfig.getRefreshToken(address);
String accessToken = DiscordConfig.getAccessToken(address);
if(refreshToken != null && accessToken != null){
return accessToken;
}
if(refreshToken == null && accessToken == null && code == null){
return null;
}
if(code != null && StringUtils.isBlank(refreshToken)){
String grantType = "authorization_code";
// Build request body
requestBody = String.format("grant_type="+grantType+"&code=%s&redirect_uri=%s",
URLEncoder.encode(code, "UTF-8"),
URLEncoder.encode(DiscordConfig.TOKEN_URL, "UTF-8"));
}else{
String grantType = "refresh_token";
//刷新令牌需要的参数
requestBody = String.format("grant_type="+grantType+"&refresh_token=%s&redirect_uri=%s",
URLEncoder.encode(refreshToken, "UTF-8"),
URLEncoder.encode(DiscordConfig.TOKEN_URL, "UTF-8"));
}
// Build request
Request request = new Request.Builder()
.url("https://discord.com/api/oauth2/token")
.post(RequestBody.create(MediaType.parse("application/x-www-form-urlencoded"), requestBody))
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.addHeader("Authorization", "Basic " + base64Credentials)
.build();
// Execute request
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful() || response.code() != 200) {
throw new IOException("Unexpected response code: " + response);
}
JSONObject json = JSON.parseObject(response.body().string());
accessToken = json.getString("access_token");
refreshToken = json.getString("refresh_token");
Integer expiresIn = json.getInteger("expires_in");
if(StringUtils.isBlank(accessToken) || StringUtils.isBlank(refreshToken)){
throw new IOException("failed to obtain the token");
}
//保存用户访问令牌和刷新令牌
DiscordConfig.addAccessToken(address,accessToken,expiresIn);
DiscordConfig.addRefreshToken(address,refreshToken,60 * 60 * 60);
return accessToken;
}
} catch (Exception e) {
DiscordConfig.deleteAccessToken(address);
DiscordConfig.deleteRefreshToken(address);
e.printStackTrace();
}
return null;
}
/**
* 根据code换取token
* @param code
* @param refreshToken
* @param merchantPojo
* @return
*/
/* public DiscordDto getToken(String code,String refreshToken,MerchantPojo merchantPojo) {
try {
Map<String, Object> formData = new HashMap<>();
if(!StringUtils.isBlank(code)){
formData.put("grant_type", "authorization_code");
formData.put("code", code);
}
if(!StringUtils.isBlank(refreshToken)){
formData.put("refresh_token", refreshToken);
formData.put("grant_type", "refresh_token");
}
//重定向配置的URL,一定要和重定向里面的地址保持一致
formData.put("redirect_uri", merchantPojo.getDcRedirectUrl());
formData.put("client_id", DiscordConfig.CLIENT_ID);
formData.put("client_secret", DiscordConfig.CLIENT_SECRET);
// 创建URL对象
DiscordDto discordDto = this.doPostForm("https://discord.com/api/oauth2/token",formData);
return discordDto;
} catch (Exception e) {
throw new RuntimeException(e);
}
}*/
/**
* 获取用户的所有服务器
* @param token
* @return
*/
public List<DiscordlaborUnionDto> findLaborUnionList(String token) {
try {
// 设置请求URL和Bearer Token
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpPost = new HttpGet("https://discord.com/api/v9/users/@me/guilds");
httpPost.setHeader("Content-Type", "application/json;charset=utf8");
httpPost.setHeader("Authorization", "Bearer " + token);
CloseableHttpResponse response = null;
// 由客户端执行(发送)Post请求
response = httpClient.execute(httpPost);
// 从响应模型中获取响应实体
HttpEntity responseEntity = response.getEntity();
if (response.getStatusLine().getStatusCode() == 200 && responseEntity != null) {
String responseJson = EntityUtils.toString(responseEntity);
JSONArray jsonArray = JSON.parseArray(responseJson);
List<DiscordlaborUnionDto> jsonArrayToStringList = JSONObject.parseArray(jsonArray.toJSONString(),DiscordlaborUnionDto.class);
return jsonArrayToStringList;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public Boolean findUserLaborUnion(String token, String guildId) {
try {
// 设置请求URL和Bearer Token
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpPost = new HttpGet("https://discord.com/api/v9/users/@me/guilds/" + guildId+"/member");
httpPost.setHeader("Content-Type", "application/json;charset=utf8");
httpPost.setHeader("Authorization", "Bearer " + token);
CloseableHttpResponse response = null;
// 由客户端执行(发送)Post请求
response = httpClient.execute(httpPost);
// 从响应模型中获取响应实体
HttpEntity responseEntity = response.getEntity();
if (response.getStatusLine().getStatusCode() == 200 && responseEntity != null) {
String responseJson = EntityUtils.toString(responseEntity);
JSONObject jsonArray = JSON.parseObject(responseJson);
if(jsonArray.get("user") != null){
return true;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 查询用户信息
* @param address
* @return
*/
public UserDto findUser(String address) {
try {
String token = this.getTokenByCode(null,address);
if(token == null){
return null;
}
// 设置请求URL和Bearer Token
CloseableHttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpPost = new HttpGet("https://discord.com/api/v9/users/@me");
httpPost.setHeader("Content-Type", "application/json;charset=utf8");
httpPost.setHeader("Authorization", "Bearer " + token);
CloseableHttpResponse response = null;
// 由客户端执行(发送)Post请求
response = httpClient.execute(httpPost);
// 从响应模型中获取响应实体
HttpEntity responseEntity = response.getEntity();
if (response.getStatusLine().getStatusCode() == 200 && responseEntity != null) {
String responseJson = EntityUtils.toString(responseEntity);
JSONObject jsonArray = JSON.parseObject(responseJson);
UserDto userDto = JSON.toJavaObject(jsonArray, UserDto.class);
return userDto;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 查询用户是否加入Discord
* @param address
* @return
*/
public Boolean joinConfirmation(String address,String guildId) {
//刷新用户token
String accessToken = this.getTokenByCode(null,address);
if(accessToken == null){
return false;
}
//查询用户工会
return this.findUserLaborUnion(accessToken,guildId);
}
public void bindUser(String id) {
Integer num = dslContext.selectCount().from(T_MEMBER).where(T_MEMBER.DISCORD_ID.eq(id)).fetchAnyInto(Integer.class);
Assert.isTrue(num == 0,"The account has been linked Discord");
}
/*public String getDiscordByCodeUrl(DcAttentionReq dcAttentionReq) {
String token = this.getRefreshToken(dcAttentionReq.getAddress());
String discordUserIdKey = "discord_user_token"+dcAttentionReq.getAddress();
//查询用户个人信息
String discordUserId = RedisUtil.get(discordUserIdKey);
if(discordUserId == null){
discordUserId = this.findUser(token).getId();
RedisUtil.setEx(discordUserIdKey,discordUserId,60 * 100);
}
try {
//先把原订单取消掉
dslContext.update(TASK_LOG).set(TASK_LOG.TASK_TYPE,4).where(TASK_LOG.ADDRESS.eq(dcAttentionReq.getAddress())
.and(TASK_LOG.STATUS.eq(3)).and(TASK_LOG.TASK_TYPE.eq(2))).execute();
TaskLogRecord log = dslContext.newRecord(TASK_LOG);
log.setAddress(dcAttentionReq.getAddress());
log.setMerchantId(1);
log.setTaskOn("001");
log.setType(dcAttentionReq.getCodeNo());
log.setStatus(3);
log.setUserId(discordUserId);
log.setTaskType(2);
log.store();
return DiscordConfig.INVITE_URL;
} catch (Exception e) {
throw new RuntimeException(e);
}
}*/
/* public TgUserReq findChannelMember(DcAttentionReq dcAttentionReq) {
TgUserReq tgUserReq = new TgUserReq();
tgUserReq.setStatus(0);
Assert.isTrue(!StringUtils.isBlank(dcAttentionReq.getAddress()) &&
!StringUtils.isBlank(dcAttentionReq.getMerchantOn()) && dcAttentionReq.getCodeNo() != null, "parameter not null");
dcAttentionReq.setAddress(dcAttentionReq.getAddress().toLowerCase());
if(dcAttentionReq.getDay() != null && dcAttentionReq.getDay() == 1){
String value = RedisUtil.get("roost_gpask_discord"+dcAttentionReq.getAddress());
if(value != null){
tgUserReq.setStatus(1);
}
}else{
TaskLogRecord taskLogRecord = merchantService.getTaskLog(dcAttentionReq.getAddress(),dcAttentionReq.getCodeNo(),3,3);
Assert.notNull(taskLogRecord,"tsak is null");
tgUserReq.setStatus(taskLogRecord.getTaskType().equals(3) ? 1 : 0);
}
return tgUserReq;
}
public String getStartTgUrl(DcFaucetReq dcFaucetReq) {
MerchantPojo merchantPojo = merchantService.getMerchant(dcFaucetReq.getCodeNo(),dcFaucetReq.getMerchantOn());
MerchantConfigPojo merchantConfigPojo = merchantService.getMerchantConfig(merchantPojo.getId());
dslContext.update(TASK_LOG).set(TASK_LOG.TASK_TYPE,4).where(TASK_LOG.ADDRESS.eq(dcFaucetReq.getAddress())
.and(TASK_LOG.STATUS.eq(3)).and(TASK_LOG.TASK_TYPE.in(1,2)).and(TASK_LOG.MERCHANT_ID.eq(merchantPojo.getId()))).execute();
TaskLogRecord log = dslContext.newRecord(TASK_LOG);
log.setMerchantId(merchantPojo.getId());
log.setAddress(dcFaucetReq.getAddress());
log.setTaskOn("00X");
log.setType(dcFaucetReq.getCodeNo());
log.setTaskType(1);
log.setStatus(3);
log.setUserId("0");
log.store();
return merchantConfigPojo.getDcInviteUrl();
}*/
}

View File

@ -0,0 +1,86 @@
package com.alive.server.service;
import com.alive.commons.config.BaseComponent;
import com.alive.commons.util.Md5Util;
import com.alive.commons.util.RequestUtil;
import com.alive.db.entity.Vo.InvitationCodeVo;
import com.alive.db.jooq.tables.records.TMemberRecord;
import com.alive.server.dto.TwitterUserDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.math.NumberUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.*;
import static com.alive.db.jooq.Tables.T_MEMBER;
@Slf4j
@Service
public class MemberService extends BaseComponent {
public List<Integer> splitAllPid(String allPid) {
if (allPid == null || allPid.isEmpty()) {
return Collections.emptyList();
}
String[] arr = allPid.split(",");
List<Integer> res = new ArrayList<>(arr.length);
for (String str : arr) {
if (NumberUtils.isNumber(str)) {
res.add(Integer.parseInt(str));
}
}
Collections.reverse(res);
return res;
}
public Integer countTwitterUser(String address) {
return dslContext.selectCount().from(T_MEMBER).where(T_MEMBER.ACCOUNT.eq(address).and(T_MEMBER.TWITTER_ID.isNotNull())).fetchAnyInto(Integer.class);
}
public Integer countDiscordUser(String address) {
return dslContext.selectCount().from(T_MEMBER).where(T_MEMBER.ACCOUNT.eq(address).and(T_MEMBER.DISCORD_ID.isNotNull())).fetchAnyInto(Integer.class);
}
public void renewalUserDiscord(String address,String discordId) {
dslContext.update(T_MEMBER).set(T_MEMBER.DISCORD_ID,discordId).where(T_MEMBER.ACCOUNT.eq(address)).execute();
}
public void renewalUserTwitter(TwitterUserDto dto, String address) {
dslContext.update(T_MEMBER).set(T_MEMBER.TWITTER_TYPE,1).set(T_MEMBER.TWITTER_USER_NAME,dto.getUsername()).set(T_MEMBER.TWITTER_ID,dto.getId())
.set(T_MEMBER.TWITTER_NAME,dto.getName()).set(T_MEMBER.TWITTER_IMG,dto.getImg()).where(T_MEMBER.ACCOUNT.eq(address)).execute();
}
public TMemberRecord fetchOne(int memberId) {
return dslContext.fetchOne(T_MEMBER, T_MEMBER.ID.eq(memberId));
}
public List<TMemberRecord> findTMemberRecordList(int memberId) {
return dslContext.select().from(T_MEMBER).where(T_MEMBER.ALL_PID.like(","+memberId+",")).fetchInto(TMemberRecord.class);
}
public Integer findTMemberRecordCount(int memberId) {
return dslContext.selectCount().from(T_MEMBER).where(T_MEMBER.ALL_PID.likeRegex(","+memberId+",")).fetchAnyInto(Integer.class);
}
public TMemberRecord fetchOneByUid(String uid) {
return dslContext.selectFrom(T_MEMBER).where(T_MEMBER.UID.eq(uid)).fetchAny();
}
public void checkPassword(int memberId, String password) {
TMemberRecord memberRecord = dslContext.fetchOne(T_MEMBER, T_MEMBER.ID.eq(memberId));
Assert.notNull(memberRecord, "account does not exist");
Assert.isTrue(Md5Util.encryptPassword(password).equals(memberRecord.getPasswordLogin()), "wrong password");
}
/* public void checkPayPassword(int memberId, String password) {
TMemberRecord memberRecord = dslContext.fetchOne(T_MEMBER, T_MEMBER.ID.eq(memberId));
Assert.notNull(memberRecord, "账号不存在");
Assert.isTrue(Md5Util.encryptPassword(password).equals(memberRecord.getPasswordPay()), "支付密码错误");
}*/
public InvitationCodeVo invitationCode() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
TMemberRecord memberRecord = dslContext.fetchOne(T_MEMBER, T_MEMBER.ID.eq(memberId));
return memberRecord != null ? new InvitationCodeVo().setInvitationCode(memberRecord.getShareCode()) : new InvitationCodeVo();
}
}

View File

@ -0,0 +1,48 @@
package com.alive.server.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.telegram.telegrambots.bots.TelegramWebhookBot;
import org.telegram.telegrambots.meta.api.methods.BotApiMethod;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.User;
import org.telegram.telegrambots.meta.TelegramBotsApi;
import org.telegram.telegrambots.meta.exceptions.TelegramApiRequestException;
import org.telegram.telegrambots.meta.api.objects.Chat;
@Slf4j
@Service
public class MyTelegramBot extends TelegramWebhookBot {
private String token ="6811525345:AAFMiaC3Q_h2kn2uXQG7m2YuaIOT9vWG0G0";
private String username ="ROOS_Test_Bot";
@Override
public BotApiMethod onWebhookUpdateReceived(Update update) {
// 处理 ChatMemberUpdated 事件
/*if (update.hasMessage() && update.getMessage().getChatMemberUpdated() != null) {
ChatMemberUpdated chatMemberUpdated = update.getMessage().getChatMemberUpdated();
processChatMemberUpdated(chatMemberUpdated);
}*/
System.out.printf("111223");
return null;
}
@Override
public String getBotUsername() {
return username;
}
@Override
public String getBotToken() {
return token;
}
@Override
public String getBotPath() {
return "http://gqydas.natappfree.cc/telegram/test";
}
}

View File

@ -0,0 +1,112 @@
package com.alive.server.service;
import com.alive.commons.util.RequestUtil;
import com.alive.db.entity.NodeBuyLog;
import com.alive.db.entity.Vo.WordNodeVo;
import com.alive.db.mapper.NodeBuyLogMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 节点认购记录Service业务层处理
*
* @author HayDen
* @date 2024-01-09
*/
@Service
public class NodeBuyLogService
{
@Autowired
private NodeBuyLogMapper nodeSubscribeMapper;
/**
* 查询节点认购记录
*
* @param id 节点认购记录ID
* @return 节点认购记录
*/
public NodeBuyLog selectNodeSubscribeById(Integer id)
{
return nodeSubscribeMapper.selectNodeSubscribeById(id);
}
public Integer countBuyLogByUserId(NodeBuyLog nodeSubscribe)
{
return nodeSubscribeMapper.countBuyLogByUserId(nodeSubscribe);
}
/**
* 查询节点认购记录列表
*
* @param nodeSubscribe 节点认购记录
* @return 节点认购记录
*/
public List<NodeBuyLog> selectNodeSubscribeList(NodeBuyLog nodeSubscribe)
{
List<NodeBuyLog> nodeSubscribeList = nodeSubscribeMapper.selectNodeSubscribeList(nodeSubscribe);
return nodeSubscribeList;
}
public NodeBuyLog findNodeSubscribeByOrderNumber(String orderNumber)
{
return nodeSubscribeMapper.findNodeSubscribeByOrderNumber(orderNumber);
}
/**
* 查询节点认购记录对象
*
* @param nodeSubscribe 节点认购记录
* @return 节点认购记录
*/
public NodeBuyLog findNodeSubscribe(NodeBuyLog nodeSubscribe)
{
nodeSubscribe = nodeSubscribeMapper.findNodeSubscribe(nodeSubscribe);
return nodeSubscribe;
}
public WordNodeVo findWordNodeVo()
{
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
WordNodeVo wordNodeVo= nodeSubscribeMapper.findWordNodeVo(memberId);
if(wordNodeVo == null || StringUtils.isBlank(wordNodeVo.getNodeName())){
wordNodeVo = new WordNodeVo();
Integer count = this.countBuyLogByUserId(new NodeBuyLog().setUserId(memberId).setStatus(2));
if(count != null && count > 0){
wordNodeVo.setStatus(2);
}else{
wordNodeVo.setStatus(3);
}
}else{
wordNodeVo.setStatus(1);
}
return wordNodeVo;
}
/**
* 修改或者添加节点认购记录
*
* @param nodeSubscribe 节点认购记录
* @return 结果
*/
public int updateOrAddNodeSubscribe(NodeBuyLog nodeSubscribe) {
if (nodeSubscribe.getId() != null){
return nodeSubscribeMapper.updateNodeSubscribe(nodeSubscribe);
}else{
return nodeSubscribeMapper.insertNodeSubscribe(nodeSubscribe);
}
}
/**
* 删除节点认购记录对象
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int deleteNodeSubscribeByIds(String ids)
{
return 0;
}
}

View File

@ -0,0 +1,172 @@
package com.alive.server.service;
import com.alive.commons.enums.WalletLogTypeEnum;
import com.alive.commons.util.CoinUtil;
import com.alive.db.entity.NodeBuyLog;
import com.alive.db.entity.NodeNftConfig;
import com.alive.db.jooq.tables.records.TMemberRecord;
import com.alive.db.jooq.tables.records.TMemberWalletRecord;
import com.alive.db.mapper.NodeNftConfigMapper;
import com.alive.server.dto.WalletOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
/**
* NFT碎片配置Service业务层处理
*
* @author HayDen
* @date 2024-01-09
*/
@Service
public class NodeNftConfigService
{
@Autowired
private NodeNftConfigMapper nodeNftConfigMapper;
@Autowired
private WalletService walletService;
@Autowired
private MemberService memberService;
/**
* 查询NFT碎片配置
*
* @param id NFT碎片配置ID
* @return NFT碎片配置
*/
public NodeNftConfig selectNodeNftConfigById(Integer id)
{
return nodeNftConfigMapper.selectNodeNftConfigById(id);
}
/**
* 查询NFT碎片配置列表
*
* @param nodeNftConfig NFT碎片配置
* @return NFT碎片配置
*/
public List<NodeNftConfig> selectNodeNftConfigList(NodeNftConfig nodeNftConfig)
{
List<NodeNftConfig> nodeNftConfigList = nodeNftConfigMapper.selectNodeNftConfigList(nodeNftConfig);
return nodeNftConfigList;
}
/**
* 查询NFT碎片配置对象
*
* @param nodeNftConfig NFT碎片配置
* @return NFT碎片配置
*/
public NodeNftConfig findNodeNftConfig(NodeNftConfig nodeNftConfig)
{
nodeNftConfig = nodeNftConfigMapper.findNodeNftConfig(nodeNftConfig);
return nodeNftConfig;
}
/**
* 修改或者添加NFT碎片配置
*
* @param nodeNftConfig NFT碎片配置
* @return 结果
*/
public int updateOrAddNodeNftConfig(NodeNftConfig nodeNftConfig) {
if (nodeNftConfig.getId() != null){
return nodeNftConfigMapper.updateNodeNftConfig(nodeNftConfig);
}else{
return nodeNftConfigMapper.insertNodeNftConfig(nodeNftConfig);
}
}
/**
* 删除NFT碎片配置对象
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int deleteNodeNftConfigByIds(String ids)
{
return nodeNftConfigMapper.deleteNodeNftConfigByIds(null);
}
/**
* 注册赠送奖励NTF碎片以及贡献值
*/
public void reward(NodeBuyLog nodeSubscribe) {
TMemberWalletRecord walletRecord= null;
WalletOperation walletOperation = null;
//先给用户自己发放奖励
{
if(nodeSubscribe.getRbitAmount().compareTo(BigDecimal.ZERO) > 0){
//购买盒子获取Rbit奖励数量
walletRecord= walletService.getWallet(nodeSubscribe.getUserId(), CoinUtil.getCoinMap().get("RBIT"));
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.RBIT_IS_COMPLIMENTARY_ON_ORDERS,nodeSubscribe.getRbitAmount(),"购买盒子赠送");
walletService.operateBalance(walletOperation);
}
if(nodeSubscribe.getNftAmount().compareTo(BigDecimal.ZERO) > 0){
walletRecord= walletService.getWallet(nodeSubscribe.getUserId(), CoinUtil.getCoinMap().get("NFTCHIP"));
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.ORDER_FREE_NFT,nodeSubscribe.getNftAmount(),"购买盒子赠送");
walletService.operateBalance(walletOperation);
}
}
//查询我的用户信息
TMemberRecord tMemberRecord = memberService.fetchOne(nodeSubscribe.getUserId());
if(tMemberRecord.getReferId().equals(0)){
//用户没有绑定上级直接返回不计算奖励
return;
}
//上级返佣
if(nodeSubscribe.getRebate().compareTo(BigDecimal.ZERO) > 0){
//返佣金额
walletRecord= walletService.getWallet(tMemberRecord.getReferId(), CoinUtil.getCoinMap().get("USDT"));
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.SUBCOMMISSION,nodeSubscribe.getRebate(),"认购下级返佣");
walletService.operateBalance(walletOperation);
//链上支付了扣回去但是需要流水统计数据
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.REBATE_TO_ACCOUNT,nodeSubscribe.getRebate().negate(),"返佣到账");
walletService.operateBalance(walletOperation);
}
{
if(nodeSubscribe.getRbitOne().compareTo(BigDecimal.ZERO) > 0){
//1代增加Rbit奖励
nodeSubscribe.setRecommendId(tMemberRecord.getReferId());
walletRecord= walletService.getWallet(nodeSubscribe.getRecommendId(), CoinUtil.getCoinMap().get("RBIT"));
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.ONE_RBIT_REWARD,nodeSubscribe.getRbitOne(),"1代Rbit奖励");
walletService.operateBalance(walletOperation);
}
if(nodeSubscribe.getNftOne().compareTo(BigDecimal.ZERO) > 0){
//1代NFT碎片奖励
walletRecord= walletService.getWallet(nodeSubscribe.getRecommendId(), CoinUtil.getCoinMap().get("NFTCHIP"));
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.ONE_NFT_REWARD,nodeSubscribe.getNftOne(),"1代NFT配件奖励");
walletService.operateBalance(walletOperation);
}
}
tMemberRecord = memberService.fetchOne(tMemberRecord.getReferId());
if(tMemberRecord.getReferId().equals(0)){
//用户没有2级上级直接返回不计算奖励
return;
}
{
if(nodeSubscribe.getRbitTwo().compareTo(BigDecimal.ZERO) > 0){
nodeSubscribe.setIndirectUserId(tMemberRecord.getReferId());
walletRecord= walletService.getWallet(nodeSubscribe.getIndirectUserId(), CoinUtil.getCoinMap().get("RBIT"));
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.TWO_RBIT_REWARD,nodeSubscribe.getRbitTwo(),"2代Rbit奖励");
walletService.operateBalance(walletOperation);
}
if(nodeSubscribe.getNftTwo().compareTo(BigDecimal.ZERO) > 0){
//2代NFT碎片奖励
walletRecord= walletService.getWallet(nodeSubscribe.getIndirectUserId(), CoinUtil.getCoinMap().get("NFTCHIP"));
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.TWO_NFT_REWARD,nodeSubscribe.getNftTwo(),"2代NFT配件奖励");
walletService.operateBalance(walletOperation);
}
}
}
}

View File

@ -0,0 +1,87 @@
package com.alive.server.service;
import com.alive.db.entity.NodePriceConfig;
import com.alive.db.mapper.NodePriceConfigMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
/**
* 节点价格区间配置Service业务层处理
*
* @author HayDen
* @date 2024-01-09
*/
@Service
public class NodePriceConfigService
{
@Autowired
private NodePriceConfigMapper nodePriceConfigMapper;
/**
* 查询节点价格区间配置
*
* @param id 节点价格区间配置ID
* @return 节点价格区间配置
*/
public NodePriceConfig selectNodePriceConfigById(Integer id)
{
return nodePriceConfigMapper.selectNodePriceConfigById(id);
}
/**
* 查询节点价格区间配置列表
*
* @param nodePriceConfig 节点价格区间配置
* @return 节点价格区间配置
*/
public List<NodePriceConfig> selectNodePriceConfigList(NodePriceConfig nodePriceConfig)
{
List<NodePriceConfig> nodePriceConfigList = nodePriceConfigMapper.selectNodePriceConfigList(nodePriceConfig);
return nodePriceConfigList;
}
/**
* 查询节点价格区间配置对象
*
* @param nodePriceConfig 节点价格区间配置
* @return 节点价格区间配置
*/
public NodePriceConfig findNodePriceConfig(NodePriceConfig nodePriceConfig)
{
nodePriceConfig = nodePriceConfigMapper.findNodePriceConfig(nodePriceConfig);
return nodePriceConfig;
}
/**
* 修改或者添加节点价格区间配置
*
* @param nodePriceConfig 节点价格区间配置
* @return 结果
*/
public int updateOrAddNodePriceConfig(NodePriceConfig nodePriceConfig) {
if (nodePriceConfig.getId() != null){
return nodePriceConfigMapper.updateNodePriceConfig(nodePriceConfig);
}else{
return nodePriceConfigMapper.insertNodePriceConfig(nodePriceConfig);
}
}
/**
* 删除节点价格区间配置对象
*
* @param ids 需要删除的数据ID
* @return 结果
*/
public int deleteNodePriceConfigByIds(String ids)
{
return 0;
}
public BigDecimal getConfigPrice(Long nodeSettingId, Integer number)
{
return nodePriceConfigMapper.getConfigPrice(nodeSettingId,number);
}
}

View File

@ -0,0 +1,273 @@
package com.alive.server.service;
import com.alive.commons.util.NumberUtil;
import com.alive.commons.util.RequestUtil;
import com.alive.server.api.account.PayNodeReq;
import com.alive.server.api.account.PayNodeSmsReq;
import com.alive.commons.config.BaseComponent;
import com.alive.db.entity.NodeBuyLog;
import com.alive.db.entity.NodeSetting;
import com.alive.db.entity.Vo.InviteVo;
import com.alive.db.entity.Vo.UserInviteVo;
import com.alive.db.entity.Vo.UserTeamVo;
import com.alive.db.entity.Vo.WordNodeVo;
import com.alive.db.jooq.tables.pojos.SysConfigPojo;
import com.alive.db.jooq.tables.records.NodeAwardSettingRecord;
import com.alive.db.mapper.NodeBuyLogMapper;
import com.alive.db.mapper.NodeSettingMapper;
import com.alive.server.web3.Web3jServer;
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.List;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static com.alive.db.jooq.Tables.*;
/**
* 节点设置Service业务层处理
*
* @author HayDen
* @date 2024-01-09
*/
@Slf4j
@Service
public class NodeSettingService extends BaseComponent {
@Resource
private NodeSettingMapper nodeSettingMapper;
@Resource
private NodeBuyLogMapper nodeSubscribeMapper;
@Autowired
private DSLContext dslContext;
@Resource
private MemberService tMemberService;
@Autowired
private Web3jServer web3jServer;
public boolean buyNode() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
Integer code = dslContext.selectCount().from(NODE_BUY_LOG).where(NODE_BUY_LOG.USER_ID.eq(memberId).and(NODE_BUY_LOG.STATUS.eq(3))).fetchAnyInto(Integer.class);
return code != null && code > 0;
}
public UserInviteVo findUserInviteVo() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
UserInviteVo vo = nodeSettingMapper.findUserInviteVo(memberId);
return vo;
}
/**
* 下单购买节点
*
* @param nodeSetting
* @param req
*/
public NodeBuyLog payNode(NodeSetting nodeSetting, PayNodeReq req) {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
Assert.isTrue(nodeSetting.getStatus().equals(1), "Not available or sold out");
Assert.isTrue(nodeSetting.getNodeTotal() > (nodeSetting.getPurchasedCount() + req.getNumber()), "Insufficient nodes");
//计算库存
int count = nodeSubscribeMapper.sumBuyCount(memberId);
Assert.isTrue((count + req.getNumber()) <= nodeSetting.getPurchaseLimit(), "Only one ROOSBOX can be purchased");
SysConfigPojo config = dslContext.select().from(SYS_CONFIG).where(SYS_CONFIG.CONFIG_KEY.eq("USDT_COLLECTION_ADDRESS")).fetchAnyInto(SysConfigPojo.class);
NodeAwardSettingRecord pojo = dslContext.selectFrom(NODE_AWARD_SETTING).where(NODE_AWARD_SETTING.NODE_SETTING_ID.eq(nodeSetting.getId())).fetchAny();
UserTeamVo userTeamVo = nodeSubscribeMapper.findUserAddressById(memberId);
userTeamVo = userTeamVo == null ? new UserTeamVo() : userTeamVo;
NodeBuyLog buyLog1 = new NodeBuyLog();
Lock lock = new ReentrantLock();
lock.lock();
try {
//查询奖励配置
if (pojo != null) {
//上级返佣
buyLog1.setRebate(req.getTatolAmount().multiply(pojo.getRebate()));
buyLog1.setRbitAmount(new BigDecimal(req.getNumber()).multiply(pojo.getRbitAmount()));
buyLog1.setRbitOne(buyLog1.getRbitAmount().multiply(pojo.getRbitOne()));
buyLog1.setRbitTwo(buyLog1.getRbitAmount().multiply(pojo.getRebateTwo()));
buyLog1.setNftAmount(new BigDecimal(req.getNumber()).multiply(pojo.getNftAmount()));
buyLog1.setNftOne(buyLog1.getNftAmount().multiply(pojo.getNftOne()));
buyLog1.setNftTwo(buyLog1.getNftAmount().multiply(pojo.getNftTwo()));
}
buyLog1.setRecommendId(userTeamVo.getId());
buyLog1.setBuyCount(req.getNumber());
buyLog1.setPayCoin(nodeSetting.getBuyCoinName());
buyLog1.setBuyAmount(req.getTatolAmount());
buyLog1.setNodeSettingId(nodeSetting.getId());
buyLog1.setStatus(1);
buyLog1.setWalletAddress(RequestUtil.getAddress());
buyLog1.setUserId(memberId);
buyLog1.setOrderNumber(NumberUtil.getUUIDBy16());
buyLog1.setOutAddress(config.getValue());
nodeSubscribeMapper.insertNodeSubscribe(buyLog1);
} catch (Exception e) {
log.error("下单出现错误,错误码:{}", e);
e.getMessage();
throw new RuntimeException(e);
} finally {
lock.unlock();
}
config = dslContext.select().from(SYS_CONFIG).where(SYS_CONFIG.CONFIG_KEY.eq("USDT_WEI")).fetchAnyInto(SysConfigPojo.class);
buyLog1.setBuyAmount(new BigDecimal(config.getValue()).multiply(buyLog1.getBuyAmount()));
buyLog1.setRebate(new BigDecimal(config.getValue()).multiply(buyLog1.getRebate()));
String address = userTeamVo.getAccount();
if (address == null || pojo.getRebate().compareTo(BigDecimal.ZERO) == 0 || !address.substring(0, 2).equals("0x") || address.length() < 30) {
buyLog1.setAddress(BigInteger.ZERO.toString());
buyLog1.setRebateRatio(new BigInteger("100"));
buyLog1.setNum(100);
} else {
BigDecimal rebate = pojo.getRebate().multiply(new BigDecimal(config.getValue()));
rebate = rebate.add(new BigDecimal(300));
Integer num = getRandom4();
rebate = rebate.multiply(new BigDecimal(num));
buyLog1.setRebateRatio(new BigInteger(rebate.stripTrailingZeros().toPlainString()));
buyLog1.setNum((num * 3) + 500 - num);
buyLog1.setAddress(Web3jServer.addressToUint160(address).add(new BigInteger("300")).subtract(new BigInteger(num.toString())).toString());
}
return buyLog1;
}
public static Integer getRandom4() {
Random random = new Random();
// 生成0到9之间的随机数包括0但不包括10
int randomNum = random.nextInt(10);
if (randomNum == 0) {
return getRandom4();
}
return randomNum;
}
/**
* 查询用户邀请列表
*/
public List<InviteVo> findInviteVoList() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
List<InviteVo> inviteVos = nodeSubscribeMapper.findInviteVoList(memberId);
for (InviteVo vo : inviteVos) {
vo.setStatus(vo.getStatus() == null ? 0 : 1);
}
return inviteVos;
}
public Boolean payNodeSms(PayNodeSmsReq req) {
NodeBuyLog nodeSubscribe = nodeSubscribeMapper.findNodeSubscribe(new NodeBuyLog().setOrderNumber(req.getOrderNumber()).setStatus(1));
Assert.isTrue(nodeSubscribe != null && nodeSubscribe.getStatus().equals(1), "Order error");
if (req.getStatus().equals(2)) {
nodeSubscribe.setStatus(4);
nodeSubscribeMapper.updateNodeSubscribe(nodeSubscribe);
return true;
}
NodeBuyLog log = nodeSubscribeMapper.findNodeSubscribe(new NodeBuyLog().setHash(req.getHash()));
Assert.isTrue(log == null, "Repetition hash");
nodeSubscribe.setStatus(2);
nodeSubscribe.setHash(req.getHash());
if (nodeSubscribe.getStatus() == 2) {
//加库存
// nodeSettingMapper.addInventory(nodeSubscribe.getBuyCount(),nodeSubscribe.getNodeId());
}
nodeSubscribeMapper.updateNodeSubscribe(nodeSubscribe);
return true;
}
/**
* 查询节点设置
*
* @param id 节点设置ID
* @return 节点设置
*/
public NodeSetting selectNodeSettingById(Integer id) {
return nodeSettingMapper.selectNodeSettingById(id);
}
/**
* 查询节点设置列表
*
* @param nodeSetting 节点设置
* @return 节点设置
*/
public List<NodeSetting> selectNodeSettingList(NodeSetting nodeSetting) {
List<NodeSetting> nodeSettingList = nodeSettingMapper.selectNodeSettingList(nodeSetting);
BigDecimal mul = new BigDecimal("100");
for (NodeSetting nodeSetting1 : nodeSettingList) {
nodeSetting1.setRebateRatio(nodeSetting1.getRebateRatio().multiply(mul));
nodeSetting1.setRbitOne(nodeSetting1.getRbitOne().multiply(mul));
nodeSetting1.setNftOne(nodeSetting1.getNftOne().multiply(mul));
nodeSetting1.setNftTwo(nodeSetting1.getNftTwo().multiply(mul));
nodeSetting1.setRebateTwo(nodeSetting1.getRebateTwo().multiply(mul));
}
return nodeSettingList;
}
/**
* 查询节点设置对象
*
* @param nodeSetting 节点设置
* @return 节点设置
*/
public NodeSetting findNodeSetting(NodeSetting nodeSetting) {
nodeSetting = nodeSettingMapper.findNodeSetting(nodeSetting);
return nodeSetting;
}
/**
* 修改或者添加节点设置
*
* @param nodeSetting 节点设置
* @return 结果
*/
public int updateOrAddNodeSetting(NodeSetting nodeSetting) {
if (nodeSetting.getId() != null) {
return nodeSettingMapper.updateNodeSetting(nodeSetting);
} else {
return nodeSettingMapper.insertNodeSetting(nodeSetting);
}
}
public List<WordNodeVo> getWOrdNodePro() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
/*web3jServer.getWeb3j().ethGetTransactionReceipt(null);
// ERC721 合约地址和查询的地址
String contractAddress = web3jServer.bftContract;
String ownerAddress = "0x1167398aa2b694edb1c24874d4c7d70340e81606";
// 加载 ERC721 合约 ABI
// 替换 YOUR_CONTRACT_ADDRESS YOUR_CONTRACT_ABI
String contractAddress = "YOUR_CONTRACT_ADDRESS";
String contractABI = "YOUR_CONTRACT_ABI";
// 创建 ERC721 合约实例
ERC721 contract = ERC721.load(contractAddress, web3j, credentials, Contract.GAS_PRICE, Contract.GAS_LIMIT);
// 获取地址的 NFT 数量
String ownerAddress = "ADDRESS_TO_CHECK"; // 替换为您要查询的地址
BigInteger nftCount = contract.balanceOf(ownerAddress).send();
System.out.println("Address " + ownerAddress + " has " + nftCount + " NFTs.");*/
return nodeSettingMapper.getWOrdNodePro(memberId);
}
public String contractAddress() {
SysConfigPojo config = dslContext.select().from(SYS_CONFIG).where(SYS_CONFIG.CONFIG_KEY.eq("CONTRACT_ADDRESS")).fetchAnyInto(SysConfigPojo.class);
return config.getValue();
}
}

View File

@ -0,0 +1,63 @@
package com.alive.server.service;
import com.alive.server.dto.TransferDto;
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.List;
import static com.alive.db.jooq.Tables.ACTIVITY_LOG;
import static com.alive.db.jooq.Tables.T_MEMBER;
/**
* 链上转账API
*/
@Slf4j
@Service
public class OnChainTransfersService {
@Autowired
private DSLContext dslContext;
@Autowired
private TokenTransferServer tokenTransferServer;
/**
* 执行链上转账换回转账HASH
* @return
*/
public void transfer() {
List<TransferDto> activityLogRecords = dslContext.select(ACTIVITY_LOG.ID,ACTIVITY_LOG.SUPERIOR_ADDRESS,ACTIVITY_LOG.ADDRESS,ACTIVITY_LOG.AMOUNT,ACTIVITY_LOG.SUPERIOR_AMOUNT,T_MEMBER.REFER_ID)
.from(ACTIVITY_LOG).leftJoin(T_MEMBER).on(ACTIVITY_LOG.ADDRESS.eq(T_MEMBER.ACCOUNT))
.where(ACTIVITY_LOG.TYPE.eq(2)
.and(ACTIVITY_LOG.TRANSFER_TYPE.eq(0))).fetchInto(TransferDto.class);
for (TransferDto logRecord : activityLogRecords){
//用户转账的地址
String address = logRecord.getAddress();
BigDecimal amount = logRecord.getAmount();
// 将以太币数量转换为 Wei
BigDecimal ethInWei = amount.multiply(BigDecimal.TEN.pow(18));
//执行用户链上转账
String hash = tokenTransferServer.transferTo(ethInWei,address,0);
if(hash == null){
continue;
}
//上级转账金额
if(logRecord.getSuperiorAddress() != null && logRecord.getSuperiorAmount().compareTo(BigDecimal.ZERO) > 0){
// 将以太币数量转换为 Wei
ethInWei = logRecord.getSuperiorAmount().multiply(BigDecimal.TEN.pow(18));
//执行用户上级链上转账
String superiorHash = tokenTransferServer.transferTo(ethInWei,logRecord.getSuperiorAddress(),0);
if(superiorHash != null){
hash = hash +" | " + superiorHash;
}
}
dslContext.update(ACTIVITY_LOG).set(ACTIVITY_LOG.TRANSFER_TYPE,1).set(ACTIVITY_LOG.HASHS,hash).where(ACTIVITY_LOG.ID.eq(logRecord.getId())).execute();
}
}
}

View File

@ -0,0 +1,167 @@
package com.alive.server.service;
import com.alive.commons.config.BaseComponent;
import com.alive.commons.enums.WalletLogTypeEnum;
import com.alive.commons.model.BasePageReq;
import com.alive.commons.util.CoinUtil;
import com.alive.commons.util.RequestUtil;
import com.alive.db.entity.Vo.*;
import com.alive.db.jooq.tables.records.NodeTaskLogRecord;
import com.alive.db.jooq.tables.records.NodeTaskRecord;
import com.alive.db.jooq.tables.records.TMemberRecord;
import com.alive.db.jooq.tables.records.TMemberWalletRecord;
import com.alive.db.mapper.PersonalCenterMapper;
import com.alive.server.api.account.TeskReq;
import com.alive.server.dto.WalletOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.math.BigDecimal;
import java.util.*;
import static com.alive.db.jooq.Tables.*;
@Slf4j
@Service
public class PersonalCenterService extends BaseComponent {
@Autowired
private PersonalCenterMapper personalCenterMapper;
@Autowired
private MemberService memberService;
@Autowired
private WalletService walletService;
public List<TeamRewardVo> findTeamRewardVoList(Integer grade) {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
List<TMemberRecord> tMemberRecords = dslContext.select().from(T_MEMBER).where(T_MEMBER.REFER_ID.eq(memberId)).fetchInto(TMemberRecord.class);
if(grade == 2 && tMemberRecords != null && tMemberRecords.size() > 0){
List<Integer> userIds = new ArrayList<>();
for (TMemberRecord user : tMemberRecords){
userIds.add(user.getId());
}
tMemberRecords = dslContext.select().from(T_MEMBER).where(T_MEMBER.REFER_ID.in(userIds)).fetchInto(TMemberRecord.class);
}
List<TeamRewardVo> list = personalCenterMapper.findTeamRewardVoList(grade,memberId);
List<TeamRewardVo> rewardVos = new ArrayList<>();
for (TMemberRecord tMemberRecord : tMemberRecords){
TeamRewardVo teamRewardVo = new TeamRewardVo();
Integer lent = tMemberRecord.getAccount().length();
teamRewardVo.setAddress(tMemberRecord.getAccount().substring(0,5)+"....."+tMemberRecord.getAccount().substring(lent-5,lent));
teamRewardVo.setNumber("0");
for(TeamRewardVo teamReward : list){
if(tMemberRecord.getAccount().equals(teamReward.getAddress())){
teamRewardVo.setNumber(new BigDecimal(teamReward.getNumber()).stripTrailingZeros().toPlainString());
}
}
rewardVos.add(teamRewardVo);
}
return rewardVos;
}
/**
* 查询个人中心数据
*/
public RecommendVo referralReward() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
RecommendVo recommendVo = personalCenterMapper.referralReward(memberId);
recommendVo = recommendVo == null ? new RecommendVo().setRebate("0").setOneBrit("0").setOneNft("0").setTwoBrit("0").setTwoNft("0") : recommendVo;
recommendVo.setInvitationCode(memberService.fetchOne(memberId).getShareCode());
recommendVo.setRebate(new BigDecimal(recommendVo.getRebate()).intValue()+"%");
recommendVo.setOneBrit(new BigDecimal(recommendVo.getOneBrit()).intValue()+"%");
recommendVo.setOneNft(new BigDecimal(recommendVo.getOneNft()).intValue()+"%");
recommendVo.setTwoBrit(new BigDecimal(recommendVo.getTwoBrit()).intValue()+"%");
recommendVo.setTwoNft(new BigDecimal(recommendVo.getTwoNft()).intValue()+"%");
//查询推荐奖励
RecommendVo recommend = personalCenterMapper.rewardStatisticsByRecommendId(memberId);
recommend = recommend == null ? new RecommendVo() : recommend;
recommendVo.setOneNftAmount(new BigDecimal(recommend.getOneNftAmount()).stripTrailingZeros().toPlainString());
recommendVo.setBitAmount(new BigDecimal(recommend.getBitAmount()).stripTrailingZeros().toPlainString());
recommendVo.setUsdtAmount(new BigDecimal(recommend.getUsdtAmount()).stripTrailingZeros().toPlainString());
RecommendVo indirectUser = personalCenterMapper.rewardStatisticsByIndirectUserId(memberId);
String amount = personalCenterMapper.sumRbitAmountById(memberId);
indirectUser = indirectUser == null ? new RecommendVo() : indirectUser;
recommendVo.setTwoNftAmount(new BigDecimal(indirectUser.getTwoNftAmount()).stripTrailingZeros().toPlainString());
recommendVo.setBitAmount((new BigDecimal(indirectUser.getBitAmount()).add(new BigDecimal(recommendVo.getBitAmount()))
.add(new BigDecimal(amount))).stripTrailingZeros().toPlainString());
return recommendVo;
}
public String minerFittings() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
TMemberWalletRecord tMemberWalletRecord = walletService.getWallet(memberId,CoinUtil.getCoinMap().get("NFTCHIP"));
return tMemberWalletRecord.getBalance().stripTrailingZeros().toPlainString();
}
public MyIntegralVo myBonusPoints() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
MyIntegralVo myIntegralVo = personalCenterMapper.myBonusPoints(memberId, CoinUtil.getCoinMap().get("POINTS"));
myIntegralVo.setMyIntegral(new BigDecimal(myIntegralVo.getMyIntegral()).stripTrailingZeros().toPlainString());
myIntegralVo.setRecommendationPoints(new BigDecimal(myIntegralVo.getRecommendationPoints()).stripTrailingZeros().toPlainString());
myIntegralVo.setIVeFinished(new BigDecimal(myIntegralVo.getIVeFinished()).stripTrailingZeros().toPlainString());
myIntegralVo.setRecommend(new BigDecimal(myIntegralVo.getRecommend()).stripTrailingZeros().toPlainString());
return myIntegralVo;
}
public List<TaskVo> recommendedCompletionList(BasePageReq basePageReq) {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
List<TaskVo> taskVos = personalCenterMapper.recommendedCompletionList(memberId,basePageReq.getOffset(),basePageReq.getSize());
for (TaskVo task : taskVos){
Integer lent = task.getAddress().length();
task.setAddress(task.getAddress().substring(0,5)+"....."+task.getAddress().substring(lent-5,lent));
task.setNumber(new BigDecimal(task.getNumber()).stripTrailingZeros().toPlainString());
}
return taskVos;
}
public List<NodeTaskVo> nodeTask() {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
List<NodeTaskVo> taskVos = new ArrayList<>();
List<NodeTaskRecord> nodeTaskRecords = dslContext.select().from(NODE_TASK).where().fetchInto(NodeTaskRecord.class);
List<NodeTaskLogRecord> logs = dslContext.select().from(NODE_TASK_LOG).where(NODE_TASK_LOG.MEMBER_ID.eq(memberId).and(NODE_TASK_LOG.STATE.in(1,2))).fetchInto(NodeTaskLogRecord.class);
for (NodeTaskRecord nodeTaskRecord : nodeTaskRecords){
NodeTaskVo nodeTaskVo = new NodeTaskVo();
nodeTaskVo.setNumber(nodeTaskRecord.getAwardValue().stripTrailingZeros().toPlainString());
nodeTaskVo.setType(nodeTaskRecord.getType());
nodeTaskVo.setState(0);
nodeTaskVo.setCoinName(CoinUtil.getCoinName(nodeTaskRecord.getCoinId()));
for (NodeTaskLogRecord log : logs){
if(nodeTaskRecord.getId().equals(log.getTaskId())){
nodeTaskVo.setState(log.getState());
nodeTaskVo.setId(log.getId());
nodeTaskVo.setCoinName(log.getCoinName());
}
}
taskVos.add(nodeTaskVo);
}
return taskVos;
}
public Map<String, Boolean> taskReward(TeskReq req) {
int memberId = Integer.parseInt(RequestUtil.getCurrentAccount());
TMemberRecord tMemberRecord = memberService.fetchOne(memberId);
NodeTaskLogRecord logs = dslContext.select().from(NODE_TASK_LOG).where(NODE_TASK_LOG.MEMBER_ID.eq(memberId).and(NODE_TASK_LOG.ID.eq(req.getId()))).fetchAnyInto(NodeTaskLogRecord.class);
Assert.isTrue(logs != null && logs.getMemberId().equals(memberId), "Order does not exist");
Assert.isTrue(logs.getState().equals(1), "Unable to claim rewards");
logs.setState(2);
logs.store();
//购买盒子获取Rbit奖励数量
TMemberWalletRecord walletRecord= walletService.getWallet(memberId, CoinUtil.getCoinMap().get(logs.getCoinName()));
WalletOperation walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.TASK_REWARD,logs.getAwardValue(),"领取任务奖励");
walletService.operateBalance(walletOperation);
//给推荐人奖励
if(logs.getRecommendValue().compareTo(BigDecimal.ZERO) != 0 && tMemberRecord.getReferId() > 0){
walletRecord= walletService.getWallet(tMemberRecord.getReferId(), CoinUtil.getCoinMap().get(logs.getCoinName()));
walletOperation = WalletOperation.buildParam(1,walletRecord.getId(), WalletLogTypeEnum.RECOMMENDER_ASSIGNMENT_REWARD,logs.getAwardValue(),"推荐人任务奖励");
walletService.operateBalance(walletOperation);
}
return (Map<String, Boolean>) new TreeMap<>().put("result",true);
}
}

View File

@ -0,0 +1,93 @@
package com.alive.server.service;
import com.alive.commons.util.JsonUtil;
import com.alive.commons.util.RedisUtil;
import com.alive.db.jooq.tables.pojos.SysConfigPojo;
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import static com.alive.db.jooq.Tables.SYS_CONFIG;
@Slf4j
@Service
public class SysConfigService {
@Autowired
private DSLContext dslContext;
public BigDecimal getNumValue(String key, BigDecimal _default) {
BigDecimal result = getNumValue(key);
return result != null ? result : _default;
}
//获取数字
public BigDecimal getNumValue(String key) {
SysConfigPojo entity = getEntityWithCache(key);
if (entity == null || entity.getValue() == null || entity.getValue().isEmpty()) {
return null;
}
return new BigDecimal(entity.getValue());
}
//获取百分数未乘1001% -> 0.01
public BigDecimal getPercentValue(String key) {
SysConfigPojo entity = getEntityWithCache(key);
if (entity == null) {
return null;
}
return new BigDecimal(entity.getValue());
}
//获取字符串配置
public String getStringValue(String key) {
SysConfigPojo entity = getEntityWithCache(key);
if (entity == null) {
return null;
}
return entity.getValue();
}
//获取json配置获取后需要强转
public Object getObjectValue(String key, Class<?> targetClass) {
SysConfigPojo entity = getEntityWithCache(key);
if (entity == null) {
return null;
}
return JsonUtil.fromJson(entity.getValue(), targetClass);
}
public Integer getIntValue(String key) {
SysConfigPojo entity = getEntityWithCache(key);
if (entity == null) {
return null;
}
return Integer.parseInt(entity.getValue());
}
private SysConfigPojo getEntityWithCache(String key) {
String cacheKey = "ids:sysConfig:" + key;
String cacheValue = RedisUtil.get(cacheKey);
if (cacheValue != null) {
return JsonUtil.fromJson(cacheValue, SysConfigPojo.class);
}
SysConfigPojo entity = dslContext.selectFrom(SYS_CONFIG)
.where(SYS_CONFIG.CONFIG_KEY.eq(key))
.fetchAnyInto(SysConfigPojo.class);
RedisUtil.setEx(cacheKey, JsonUtil.toJson(entity), 5);
return entity;
}
public void update(String key, String value) {
dslContext.update(SYS_CONFIG)
.set(SYS_CONFIG.VALUE, value)
.where(SYS_CONFIG.CONFIG_KEY.eq(key))
.execute();
}
}

View File

@ -0,0 +1,291 @@
package com.alive.server.service;
import com.alive.server.dto.*;
import com.alive.commons.util.DateUtils;
import com.alive.db.jooq.tables.records.ActivityLogRecord;
import com.alive.server.config.DiscordConfig;
import com.alive.server.config.TwitterConfig;
import lombok.extern.slf4j.Slf4j;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.sql.Timestamp;
import java.util.*;
import static com.alive.db.jooq.Tables.*;
@Slf4j
@Service
public class TaskService {
@Autowired
private DSLContext dslContext;
@Autowired
private TwitterService twitterService;
@Autowired
private DiscordService discordService;
@Autowired
private TelegramServer telegramServer;
/**
* 检测用户是否完成任务 关注改名
*/
public void optimismExec() {
List<ActivityLogRecord> activityLogRecords = dslContext.selectFrom(ACTIVITY_LOG).where(ACTIVITY_LOG.TYPE.eq(1)
.and(ACTIVITY_LOG.CONFIG_TYPE.in(1,5))).fetch();
if(activityLogRecords == null || activityLogRecords.size() <= 0){
return;
}
for (ActivityLogRecord log : activityLogRecords){
if(log.getConfigType().equals(1)){
//执行检查关注操作
String accessToken = TwitterConfig.getAccessToken(log.getAddress());
//重新刷新token
if(accessToken == null && twitterService.requestBearerToken(log.getAddress(),null) == null){
continue;
}
accessToken = TwitterConfig.getAccessToken(log.getAddress());
//查询用户自己的账号
TwitterUserDto twitterUserDto = twitterService.getUserInfoByToken(accessToken);
//执行关注
AttentionDto attentionDto = twitterService.attention(accessToken,twitterUserDto.getId(),TwitterConfig.DEVELOPERS);
if(attentionDto != null && attentionDto.getFollowing()){
log.setType(2);
}else{
log.setType(3);
}
}else{
String accessToken = TwitterConfig.getAccessToken(log.getAddress());
//重新刷新token
if(accessToken == null && twitterService.requestBearerToken(log.getAddress(),null) == null){
continue;
}
accessToken = TwitterConfig.getAccessToken(log.getAddress());
TwitterUserDto twitterUserDto = twitterService.getUserInfoByToken(accessToken);
//需要修改推特的后缀名
String name = log.getMark();
String twitterName = twitterUserDto.getName().substring(twitterUserDto.getName().length() - name.length(),twitterUserDto.getName().length());
if(name.toLowerCase().equals(twitterName.toLowerCase())){
//任务完成
log.setType(2);
//更新用户推特信息
dslContext.update(T_MEMBER).set(T_MEMBER.TWITTER_IMG,twitterUserDto.getImg()).set(T_MEMBER.TWITTER_NAME,twitterUserDto.getName())
.set(T_MEMBER.TWITTER_USER_NAME,twitterUserDto.getUsername()).set(T_MEMBER.TWITTER_ID,twitterUserDto.getId())
.where(T_MEMBER.ACCOUNT.eq(log.getAddress())).execute();
}
}
if(log.getType().equals(1) && DateUtils.addMinute(log.getCreateTime(),120).getTime() < System.currentTimeMillis()){
//任务创建超过2小时任务失败
log.setType(3);
}
//更新数据
if(log.getType().equals(2) || log.getType().equals(3)){
log.store();
}
if(log.getType().equals(2)){
//增加用户资产统计
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getAddress())).execute();
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getSuperiorAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getSuperiorAddress())).execute();
}
}
}
/**
* 检测用户是否完成任务 转载点赞
*/
public void activeExec() {
List<TwitterTransshipmentDto> activityLogRecords = dslContext.select(ACTIVITY_LOG.ID.as("id"),
ACTIVITY_LOG.CREATE_TIME.as("createTime"),ACTIVITY_LOG.ACTIVITY_CONFIG_ID.as("activityConfigId")
,ACTIVITY_LOG.ADDRESS.as("address"),ACTIVITY_LOG.TYPE.as("type")
,ACTIVITY_LOG.AMOUNT.as("amount"),ACTIVITY_LOG.SUPERIOR_AMOUNT.as("superiorAmount"),ACTIVITY_LOG.SUPERIOR_ADDRESS.as("superiorAddress"),ACTIVITY_LOG.CONFIG_TYPE.as("configType")
,ACTIVITY_LOG.MARK.as("mark"),T_MEMBER.TWITTER_ID.as("twitterId"))
.from(ACTIVITY_LOG).leftJoin(T_MEMBER).on(
ACTIVITY_LOG.ADDRESS.eq(T_MEMBER.ACCOUNT)).where(ACTIVITY_LOG.TYPE.eq(1)
.and(ACTIVITY_LOG.CONFIG_TYPE.in(2,3,5))).fetchInto(TwitterTransshipmentDto.class);
if(activityLogRecords == null || activityLogRecords.size() <= 0){
return;
}
//推文ID+推特ID == 点赞的用户
Map<String,String> thumbsUpmap = new HashMap<>();
{
//点赞的推文id
Set<String> thumbsUp = new HashSet<>();
//推特ID == 用户地址
Map<String,String> twitterMap = new HashMap<>();
activityLogRecords.forEach(a -> {
if(a.getConfigType().equals(3)){
thumbsUp.add(a.getMark());
twitterMap.put(a.getTwitterId(),a.getAddress());
}
});
for (String key : twitterMap.keySet()){
String twId = key;
String address = twitterMap.get(key);
//查询出该推特用户 点赞了那些文章,返回推文的ID
List<String> ids = twitterService.thumbsUpListByTwitterId(twId,TwitterConfig.getAccessToken(address));
if(ids == null){
continue;
}
//查询推特那些用户进行的点赞
for (String id : ids){
thumbsUpmap.put(id+twId,address);
}
}
}
//推文ID+推特ID == 转载的用户
Map<String,String> transshipmentMap = new HashMap<>();
{
//转载的推文id
Set<String> transshipment = new HashSet<>();
activityLogRecords.forEach(a -> {
if(a.getConfigType().equals(2)){
transshipment.add(a.getMark());
}
});
//查询推特那些用户进行的转载
for (String twid : transshipment){
List<TransshipmentUserDto> list = twitterService.transmitUserList(twid);
if(list == null){
continue;
}
list.forEach(t ->{
transshipmentMap.put(twid+t.getId(),"1");
});
}
}
for (TwitterTransshipmentDto log : activityLogRecords){
ActivityLogRecord logRecord = dslContext.newRecord(ACTIVITY_LOG);
logRecord.setId(log.getId());
if(log.getConfigType().equals(2)){
//执行检查推文转载
String value = transshipmentMap.get(log.getMark()+log.getTwitterId());
logRecord.setType(value != null ? 2 : log.getType());
}else if(log.getConfigType().equals(3)){
String value = thumbsUpmap.get(log.getMark()+log.getTwitterId());
logRecord.setType(value != null ? 2 : log.getType());
}
logRecord.setEndTime(new Timestamp(System.currentTimeMillis()));
if(logRecord.getType() != null && logRecord.getType().equals(2)){
//增加用户资产统计
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getAddress())).execute();
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getSuperiorAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getSuperiorAddress())).execute();
//更新数据
logRecord.update();
}else if(log.getType().equals(1) && DateUtils.addMinute(log.getCreateTime(),120).getTime() < System.currentTimeMillis()){
//任务创建超过2小时任务失败
logRecord.setType(3);
logRecord.update();
}
}
}
/**
* 加入Discord
*/
public void addDiscord() {
List<DiscordTransshipmentDto> activityLogRecords = dslContext.select(ACTIVITY_LOG.ID.as("id"),ACTIVITY_LOG.ACTIVITY_CONFIG_ID.as("activityConfigId")
,ACTIVITY_LOG.ADDRESS.as("address"),ACTIVITY_LOG.TYPE.as("type")
,ACTIVITY_LOG.AMOUNT.as("amount"),ACTIVITY_LOG.CREATE_TIME.as("createTime"),ACTIVITY_LOG.SUPERIOR_AMOUNT.as("superiorAmount"),ACTIVITY_LOG.SUPERIOR_ADDRESS.as("superiorAddress"),
ACTIVITY_LOG.CONFIG_TYPE.as("configType"),ACTIVITY_LOG.MARK.as("mark"),T_MEMBER.DISCORD_ID.as("discordId"))
.from(ACTIVITY_LOG).leftJoin(T_MEMBER).on(
ACTIVITY_LOG.ADDRESS.eq(T_MEMBER.ACCOUNT)).where(ACTIVITY_LOG.TYPE.eq(1)
.and(ACTIVITY_LOG.CONFIG_TYPE.in(6))).fetchInto(DiscordTransshipmentDto.class);
if(activityLogRecords == null || activityLogRecords.size() <= 0){
return;
}
for (DiscordTransshipmentDto log : activityLogRecords){
ActivityLogRecord logRecord = dslContext.newRecord(ACTIVITY_LOG);
logRecord.setId(log.getId());
Boolean outcome = discordService.joinConfirmation(log.getAddress(), DiscordConfig.CHANNEL_ID);
if(outcome){
logRecord.setType(2);
log.setType(2);
}
if(log.getType().equals(1) && DateUtils.addMinute(log.getCreateTime(),120).getTime() < System.currentTimeMillis()){
//任务创建超过2小时任务失败
logRecord.setType(3);
log.setType(3);
}
if(!log.getType().equals(1)){
logRecord.update();
}
if(log.getType().equals(2)){
//增加用户资产统计
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getAddress())).execute();
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getSuperiorAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getSuperiorAddress())).execute();
}
}
}
/**
* 乐观验证
*/
public void optimisticValidation() {
List<ActivityLogRecord> logRecords = dslContext.select(ACTIVITY_LOG.ID,ACTIVITY_LOG.ADDRESS,ACTIVITY_LOG.AMOUNT,ACTIVITY_LOG.SUPERIOR_ADDRESS,ACTIVITY_LOG.SUPERIOR_AMOUNT).
from(ACTIVITY_LOG).where(ACTIVITY_LOG.CONFIG_TYPE.in(4,7).and(ACTIVITY_LOG.TYPE.eq(1))).fetchInto(ActivityLogRecord.class);
if(logRecords != null && logRecords.size() > 0){
List<Integer> ids = new ArrayList<>();
for (ActivityLogRecord log : logRecords){
ids.add(log.getId());
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getAddress())).execute();
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getSuperiorAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getSuperiorAddress())).execute();
}
dslContext.update(ACTIVITY_LOG).set(ACTIVITY_LOG.TYPE,2).where(ACTIVITY_LOG.ID.in(ids)).execute();
}
}
/**
* 加入TG
*/
public void addTg() {
List<DiscordTransshipmentDto> activityLogRecords = dslContext.select(ACTIVITY_LOG.ID.as("id"),ACTIVITY_LOG.ACTIVITY_CONFIG_ID.as("activityConfigId")
,ACTIVITY_LOG.ADDRESS.as("address"),ACTIVITY_LOG.TYPE.as("type")
,ACTIVITY_LOG.AMOUNT.as("amount"),ACTIVITY_LOG.CREATE_TIME.as("createTime"),ACTIVITY_LOG.SUPERIOR_AMOUNT.as("superiorAmount"),ACTIVITY_LOG.SUPERIOR_ADDRESS.as("superiorAddress"),
ACTIVITY_LOG.CONFIG_TYPE.as("configType"),ACTIVITY_LOG.MARK.as("mark"),T_MEMBER.TG_ID.as("tgId"))
.from(ACTIVITY_LOG).leftJoin(T_MEMBER).on(
ACTIVITY_LOG.ADDRESS.eq(T_MEMBER.ACCOUNT)).where(ACTIVITY_LOG.TYPE.eq(1)
.and(ACTIVITY_LOG.CONFIG_TYPE.in(10))).fetchInto(DiscordTransshipmentDto.class);
if(activityLogRecords == null || activityLogRecords.size() <= 0){
return;
}
for (DiscordTransshipmentDto log : activityLogRecords){
ActivityLogRecord logRecord = dslContext.newRecord(ACTIVITY_LOG);
logRecord.setId(log.getId());
if(log.getTgId() != null){
Boolean outcome = telegramServer.joinConfirmation(log.getTgId());
if(outcome){
logRecord.setType(2);
log.setType(2);
}
}
if(log.getType().equals(1) && DateUtils.addMinute(log.getCreateTime(),120).getTime() < System.currentTimeMillis()){
//任务创建超过2小时任务失败
logRecord.setType(3);
log.setType(3);
}
if(!log.getType().equals(1)){
logRecord.update();
}
if(log.getType().equals(2)){
//增加用户资产统计
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getAddress())).execute();
dslContext.update(ACTIVITY_STATISTICS).set(ACTIVITY_STATISTICS.AMOUNT,ACTIVITY_STATISTICS.AMOUNT.add(log.getSuperiorAmount())).where(ACTIVITY_STATISTICS.ADDRESS.eq(log.getSuperiorAddress())).execute();
}
}
}
}

View File

@ -0,0 +1,174 @@
package com.alive.server.service;
import com.alive.server.config.TelegramConfig;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.telegram.telegrambots.bots.TelegramLongPollingBot;
import org.telegram.telegrambots.meta.api.methods.groupadministration.GetChatMember;
import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
import org.telegram.telegrambots.meta.api.objects.Message;
import org.telegram.telegrambots.meta.api.objects.Update;
import org.telegram.telegrambots.meta.api.objects.chatmember.ChatMember;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.InlineKeyboardMarkup;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
import java.util.ArrayList;
import java.util.List;
import static com.alive.db.jooq.Tables.T_MEMBER;
@Slf4j
@Service
@Component
public class TelegramServer extends TelegramLongPollingBot {
@Autowired
private DSLContext dslContext;
@Autowired
public TelegramServer(DSLContext dslContext) {
this.dslContext = dslContext;
}
private InlineKeyboardMarkup keyboardM1;
@Override
public void onUpdateReceived(Update update) {
var msg = update.getMessage();
if(msg == null){
return;
}
var user = msg.getFrom();
//用户发送的消息,消息长度必须大于10以上 /start 0x505f87Bc247c907dc8005fC5d60d020Ae459CE09
String text = msg.getText();
if(user == null || text == null || text.length() < 10){
return;
}
if (msg.getText().substring(0,6).equals("/start")) {
//获取到用户的地址
String address = msg.getText().substring(7,msg.getText().length()).toLowerCase();
//获取到用户的TG id
Long tgUserId = user.getId();
String userAddress = dslContext.select(T_MEMBER.ACCOUNT).from(T_MEMBER).where(T_MEMBER.TG_ID.eq(tgUserId.toString())).limit(1).fetchAnyInto(String.class);
if(userAddress != null){
//该TG账号已经被绑定过了,绑定地址为 userAddress
this.sendText(user.getId(),"Your account has been bound to an address 【"+userAddress+"");
return;
}
//开始绑定用户地址
Integer outcome = dslContext.update(T_MEMBER).set(T_MEMBER.TG_ID,tgUserId.toString()).where(T_MEMBER.ACCOUNT.eq(address)).execute();
if(outcome <= 0){
//该账号不存在
this.sendText(user.getId(),"The account is not registered");
return;
}
InlineKeyboardButton joinUs = InlineKeyboardButton.builder()
.text("加入我们")
.url(TelegramConfig.ADD_TG_URL)
.build();
//此按钮 Tutorial 点击可以跳转到地址https://core.telegram.org/bots/api
InlineKeyboardButton url = InlineKeyboardButton.builder()
.text("官网链接")
.url(TelegramConfig.APP_TG_URL)
.build();
List<InlineKeyboardButton> list = new ArrayList<>();
list.add(joinUs);
list.add(url);
keyboardM1 = InlineKeyboardMarkup.builder()
.keyboardRow(list).build();
sendMenu(user.getId(), "<b>欢迎加入roos官网TG请根据需求进行以下操作</b>",keyboardM1);
}
}
/**
* 发送消息到用户或者频道 后面是消息内容
* @param id
* @param txt
* @param kb 消息下面跟着几个按钮可以点击的
*/
public void sendMenu(Long id, String txt, InlineKeyboardMarkup kb){
SendMessage sm = SendMessage.builder().chatId(id.toString())
.parseMode("HTML").text(txt)
.replyMarkup(kb).build();
try {
execute(sm);
} catch (TelegramApiException e) {
throw new RuntimeException(e);
}
}
/**
* 发送消息到用户或者频道 后面是消息内容
* @param id
* @param msg
*/
private void scream(Long id, Message msg) {
if(msg.hasText()){
sendText(id, msg.getText().toLowerCase());
} else{
//copyMessage(id, msg.getMessageId()); //We can't really scream a sticker
}
}
/**
* 发送消息到用户或者频道 后面是消息内容
* @param id
* @param what
*/
public void sendText(Long id, String what){
SendMessage sm = SendMessage.builder()
.chatId(id.toString())
.text(what).build();
try {
execute(sm);
} catch (TelegramApiException e) {
throw new RuntimeException(e);
}
}
@Override
public String getBotUsername() {
// 返回您的机器人的用户名
return TelegramConfig.TG_BOT_NAME;
}
@Override
public String getBotToken() {
// 返回您的机器人的令牌
return TelegramConfig.TG_BOT_TOKEN;
}
public Boolean joinConfirmation(String tgId) {
// 处理接收到的消息 -1002019878988 6174699932
// 创建一个 GetChatMembersCount 对象 5331549827
// 使用 execute 方法发送请求并获取 ChatMembersCount 对象
try { //创造者creator 成员member 未加入的left left
// 创建一个 GetChatMember 对象
GetChatMember getChatMember = new GetChatMember(TelegramConfig.TG_BOT_TEAM_ID, Long.parseLong(tgId));
// 使用 execute 方法发送请求并获取 ChatMember 对象
ChatMember chatMember = execute(getChatMember);
String status = chatMember.getStatus().toLowerCase();
//Creator: 聊天创建者
//Administrator: 管理员
//Member: 普通成员
//Restricted: 受限成员
//Left: 已退出聊天
//Kicked: 已踢出聊天
if(status.equals("creator") || status.equals("administrator") || status.equals("member")){
return true;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return false;
}
}

View File

@ -0,0 +1,114 @@
package com.alive.server.service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.web3j.abi.FunctionEncoder;
import org.web3j.abi.TypeReference;
import org.web3j.abi.datatypes.Address;
import org.web3j.abi.datatypes.Function;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.Uint;
import org.web3j.abi.datatypes.generated.Uint256;
import org.web3j.crypto.Credentials;
import org.web3j.crypto.RawTransaction;
import org.web3j.crypto.TransactionEncoder;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.DefaultBlockParameterName;
import org.web3j.protocol.core.methods.request.Transaction;
import org.web3j.protocol.core.methods.response.EthEstimateGas;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.EthSendTransaction;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import org.web3j.tx.gas.ContractGasProvider;
import org.web3j.tx.gas.DefaultGasProvider;
import org.web3j.utils.Numeric;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
@Slf4j
@Service
@Component
public class TokenTransferServer {
/**
* 节点的 RPC URL
*/
@Value("${chain.transfer.rpcUrl}")
private String rpcUrl;
/**
* ERC-20代币合约地址
*/
@Value("${chain.transfer.erc20}")
private String contractAddress;
/**
* 发送方的私钥
*/
@Value("${chain.transfer.privateKey}")
private String privateKey;
/**
* ERC20转账到指定地址
* @param amount
* @param toAddress
*/
public String transferTo(BigDecimal amount, String toAddress, Integer non) {
try {
Web3j web3j = Web3j.build(new HttpService(rpcUrl));
Credentials credentials = Credentials.create(privateKey);
Function function = new Function(
"transfer",
Arrays.asList(new Address(toAddress), new Uint256(amount.toBigInteger())),
Collections.emptyList()
);
String encodedFunction = FunctionEncoder.encode(function);
BigInteger gasLimit = BigInteger.valueOf(21000);
BigInteger nonce = web3j.ethGetTransactionCount(credentials.getAddress(), DefaultBlockParameterName.PENDING).send().getTransactionCount().add(new BigInteger(non.toString()));
BigInteger gasPrice = web3j.ethGasPrice().send().getGasPrice();
RawTransaction rawTransaction = RawTransaction.createTransaction(
nonce,
gasPrice,
gasLimit,
contractAddress,
encodedFunction
);
byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials);
String hexValue = Numeric.toHexString(signedMessage);
EthSendTransaction ethSendTransaction = web3j.ethSendRawTransaction(hexValue).send();
if (ethSendTransaction.hasError()) {
if(ethSendTransaction.getError().getMessage().equals("nonce too low")){
return this.transferTo(amount, toAddress, non + 1);
} else {
log.error("Token transfer failed. Error: {}", ethSendTransaction.getError().getMessage());
}
} else {
String transactionHash = ethSendTransaction.getTransactionHash();
// 等待交易确认3秒不然nonce确认不过来会导致错误
Thread.sleep(3000);
EthGetTransactionReceipt receipt = web3j.ethGetTransactionReceipt(transactionHash).send();
if (receipt.getTransactionReceipt().isPresent()) {
log.info("Transaction confirmed. Hash: {}", transactionHash);
} else {
log.warn("Transaction might not be confirmed yet. Hash: {}", transactionHash);
}
return transactionHash;
}
} catch (Exception e) {
log.error("ERC20转账错误: {}", e.getMessage());
}
return null;
}
}

View File

@ -0,0 +1,633 @@
package com.alive.server.service;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alive.server.dto.AttentionDto;
import com.alive.server.dto.TransshipmentUserDto;
import com.alive.server.dto.TwitterDto;
import com.alive.server.dto.TwitterUserDto;
import com.alive.commons.config.BaseComponent;
import com.alive.server.config.TwitterConfig;
import lombok.extern.slf4j.Slf4j;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;
import oauth.signpost.exception.OAuthCommunicationException;
import oauth.signpost.exception.OAuthExpectationFailedException;
import oauth.signpost.exception.OAuthMessageSignerException;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.io.*;
import java.net.*;
import java.util.*;
import static com.alive.db.jooq.Tables.T_MEMBER;
@Slf4j
@Service
public class TwitterService extends BaseComponent {
@Autowired
private DSLContext dslContext;
public static String codeChallenge = "0ioze5m20493ny2";
/**
* 生成推文转发链接
* @param authorizationReq
* @return
*/
/* public String getTtTweetsUrl(TwitterAuthorizationReq authorizationReq){
String url = "https://twitter.com/";
MerchantPojo merchantPojo = merchantService.getMerchant(authorizationReq.getCodeNo(),authorizationReq.getMerchantOn());
MerchantConfigPojo merchantConfigPojo = merchantService.getMerchantConfig(merchantPojo.getId());
url += merchantConfigPojo.getTtUserName();
url += "/status/" + merchantConfigPojo.getTtTweetsId() +"?s=20";
return url;
}*/
/**
* 返回授权的地址
* @param address
* @return
*/
public String getAuthorizationUrl(String address){
String url = "https://twitter.com/i/oauth2/authorize?";
url += "client_id="+ TwitterConfig.CLIENT_ID;
//访问权限
url += "&scope="+ "tweet.read%20tweet.write%20offline.access%20tweet.moderate.write%20users.read%20follows.read%20follows.write%20like.read";
url += "&response_type=code";
//回调地址
url += "&redirect_uri="+TwitterConfig.CALLBACK_URL;
//用户地址
url += "&state="+address;
url += "&code_challenge="+codeChallenge+"&code_challenge_method=plain";
return url;
}
/**
* 用户关注
* @param token 授权换取的用户token
* @param userId 用户自己的ID
* @param targetUserId 被关注的推特用户ID
* @return
* @throws Exception
*/
public AttentionDto attention(String token, String userId, String targetUserId) {
try {
String urlAdress = "https://api.twitter.com/2/users/" + userId + "/following";
URL url12 = new URL(urlAdress);
HttpURLConnection connection = (HttpURLConnection) url12.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "Bearer " + token);
JSONObject requestBody = new JSONObject();
//需要关注的用户ID
requestBody.put("target_user_id", targetUserId);
String requestBodyString = requestBody.toString();
connection.setDoOutput(true);
OutputStream outputStream = connection.getOutputStream();
outputStream.write(requestBodyString.getBytes());
outputStream.flush();
outputStream.close();
int responseCode = connection.getResponseCode();
InputStream inputStream;
if (responseCode == 429) {
Assert.notNull(null, "limiting frequency");
}
if (responseCode >= 200 && responseCode < 400) {
inputStream = connection.getInputStream();
} else {
inputStream = connection.getErrorStream();
}
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuilder responseBuilder = new StringBuilder();
while ((line = reader.readLine()) != null) {
responseBuilder.append(line);
}
reader.close();
String response = responseBuilder.toString();
if (JSON.parseObject(response).get("data") != null) {
JSONObject json = JSON.parseObject(JSON.parseObject(response).get("data").toString());
AttentionDto attentionDto = new AttentionDto();
Object ret = json.get("following");
attentionDto.setFollowing(Boolean.parseBoolean(ret == null ? "false" : ret.toString()));
ret = json.get("pending_follow");
attentionDto.setPending_follow(Boolean.parseBoolean(ret == null ? "false" : ret.toString()));
return attentionDto;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 根据code获取用户token
* @param address 授权地址
* @param code 获取token
* @return
*/
public TwitterDto requestBearerToken(String address, String code) {
try {
TwitterDto twitterDto = new TwitterDto();
String clientId = URLEncoder.encode(TwitterConfig.CLIENT_ID, "UTF-8");
String clientSecret = URLEncoder.encode(TwitterConfig.CLIENT_SECRET, "UTF-8");
String credentials = clientId + ":" + clientSecret;
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
String redirectURI = TwitterConfig.CALLBACK_URL;
URL url = new URL("https://api.twitter.com/2/oauth2/token");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Authorization", "Basic " + base64Credentials);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
connection.setDoOutput(true);
connection.setDoInput(true);
String data = "";
String refreshToken = TwitterConfig.getRefreshToken(address);
String accessToken = TwitterConfig.getAccessToken(address);
if(!StringUtils.isBlank(refreshToken) && !StringUtils.isBlank(accessToken)){
//避免用户重复获取token
twitterDto.setAccessToken(accessToken);
twitterDto.setRefreshToken(refreshToken);
return twitterDto;
}
if(StringUtils.isBlank(refreshToken) && code == null){
return null;
}
if(StringUtils.isBlank(refreshToken) && code != null){
String grantType = "authorization_code";
//获取令牌需要的参数 code_verifier 需要和获取code传入参数 code_challenge 保持一致
data = "grant_type=" + grantType + "&code=" + code + "&redirect_uri=" + redirectURI+
"&client_id="+TwitterConfig.CLIENT_ID+"&client_secret="+TwitterConfig.CLIENT_SECRET+"&code_verifier="+codeChallenge;
}else{
String grantType = "refresh_token";
//刷新令牌需要的参数
data = "refresh_token="+refreshToken+"&grant_type=" + grantType + "&client_id="+TwitterConfig.CLIENT_ID+
"&client_secret="+TwitterConfig.CLIENT_SECRET+"&code_verifier="+codeChallenge;
}
connection.getOutputStream().write(data.getBytes("UTF-8"));
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
String jsonResponse = response.toString();
JSONObject json = JSON.parseObject(jsonResponse);
accessToken = json.getString("access_token");
twitterDto.setAccessToken(accessToken == null ? null : accessToken);
refreshToken = json.getString("refresh_token");
twitterDto.setRefreshToken(refreshToken == null ? null : refreshToken);
TwitterConfig.addAccessToken(address,accessToken,6000);
TwitterConfig.addRefreshToken(address,refreshToken,60 * 60 * 168);
return twitterDto;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* 获取开发者推特token
* @return
*/
public String getTwitterToken(){
try {
String consumerKey = URLEncoder.encode(TwitterConfig.CONSUMER_KEY, "UTF-8");
String consumerSecret = URLEncoder.encode(TwitterConfig.CONSUMER_SECRET, "UTF-8");
String credentials = consumerKey + ":" + consumerSecret;
String base64Credentials = Base64.getEncoder().encodeToString(credentials.getBytes());
//authorization_coderefresh_tokenclient_credentials
String grantType = "client_credentials";
URL url = new URL("https://api.twitter.com/oauth2/token");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Authorization", "Basic " + base64Credentials);
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
connection.setDoOutput(true);
connection.setDoInput(true);
String data = "grant_type=" + grantType +
"&client_id="+TwitterConfig.CLIENT_ID+"&client_secret="+TwitterConfig.CLIENT_SECRET+"&code_verifier=challenge";
connection.getOutputStream().write(data.getBytes("UTF-8"));
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
// Extract bearer token from JSON response
String jsonResponse = response.toString();
JSONObject json = JSON.parseObject(jsonResponse);
return json.get("access_token").toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取开发者账号信息
* @return
*/
public JSONObject getUserInfo() throws Exception {
CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(TwitterConfig.CONSUMER_KEY, TwitterConfig.CONSUMER_SECRET);
consumer.setTokenWithSecret(TwitterConfig.ACCESS_TOKEN, TwitterConfig.ACCESS_TOKEN_SECRET);
// 创建HttpClient对象
HttpClient httpClient = this.setProxy();
// 创建API请求例如获取用户的时间线
try {
URIBuilder uriBuilder = new URIBuilder("https://api.twitter.com/2/users/me");
ArrayList<NameValuePair> queryParameters;
queryParameters = new ArrayList<>();
queryParameters.add(new BasicNameValuePair("user.fields", "id,name,username,profile_image_url,public_metrics"));
queryParameters.add(new BasicNameValuePair("expansions", "pinned_tweet_id"));
uriBuilder.addParameters(queryParameters);
HttpGet request = new HttpGet(uriBuilder.build());
request.setHeader("Content-Type","application/json");
consumer.sign(request);
// 创建参数列表
HttpResponse response = httpClient.execute(request);
// 处理API响应
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
if (statusCode == 200) {
System.out.println(responseBody);
return JSONObject.parseObject(responseBody);
} else {
System.out.println(responseBody);
return JSONObject.parseObject(responseBody);
}
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 设置请求代理
* @return
*/
private HttpClient setProxy(){
// 创建HttpClientBuilder对象
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
HttpClient client = httpClientBuilder.build();;
return client;
}
/**
* 根据用户token换取用户信息
* @param token
* @return
*/
public TwitterUserDto getUserInfoByToken(String token){
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try {
// Twitter API endpoint
String endpoint = "https://api.twitter.com/2/users/me";
// 构造带有参数的 URL
String urlWithParams = endpoint + "?user.fields=name,pinned_tweet_id,profile_image_url";
// 创建 URL 对象
URL url = new URL(urlWithParams);
URLConnection connection = url.openConnection();
connection.setRequestProperty("Authorization", "Bearer " + token);
connection.setRequestProperty("Content-Type","application/json");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null)
{
result.append(line);
}
TwitterUserDto dto = new TwitterUserDto();
JSONObject json = JSONObject.parseObject(result.toString());
JSONObject user = (JSONObject)json.get("data");
if(user != null){
dto.setId(user.get("id").toString());
dto.setName(user.get("name").toString());
dto.setImg(user.get("profile_image_url").toString());
dto.setUsername(user.get("username").toString());
}
return dto;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 换取token查询用户信息
* @param address
*/
public TwitterUserDto getTwitterToken(String address,String token) {
TwitterUserDto twitterUserDto = this.getUserInfoByToken(token);
Assert.notNull(twitterUserDto, "get twitter user error");
return twitterUserDto;
}
/**
* 根据推文ID查询那些用户进行了转发
* @param tweetId
* @return
*/
public List<TransshipmentUserDto> transmitUserList(String tweetId){
CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(TwitterConfig.CONSUMER_KEY, TwitterConfig.CONSUMER_SECRET);
consumer.setTokenWithSecret(TwitterConfig.ACCESS_TOKEN, TwitterConfig.ACCESS_TOKEN_SECRET);
// 创建HttpClient对象
HttpClient httpClient = this.setProxy();
// 创建API请求例如获取用户的时间线
try {
URIBuilder uriBuilder = new URIBuilder("https://api.twitter.com/2/tweets/"+tweetId+"/retweeted_by");
HttpGet request = new HttpGet(uriBuilder.build());
request.setHeader("Content-Type","application/json");
consumer.sign(request);
// 创建参数列表
HttpResponse response = httpClient.execute(request);
// 处理API响应
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
if (statusCode == HttpURLConnection.HTTP_OK) {
List<TransshipmentUserDto> list = new ArrayList<>();
// 读取响应
//默认最大返回100条
JSONObject array = JSONObject.parseObject(responseBody);
JSONArray arr = array.getJSONArray("data");
if(arr == null){
return list;
}
for (int i = 0; i < arr.size(); i++) {
list.add(arr.getObject(i,TransshipmentUserDto.class));
}
// 打印响应
return list;
} else {
System.out.println("Failed to fetch data from Twitter API. Response code: " + statusCode);
}
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 根据用户token和用户ID查询用户喜欢的推文
* @param token
* @return
*/
public List<String> thumbsUpListByTwitterId(String twitterId, String token){
if(twitterId == null || token == null){
return null;
}
StringBuilder result = new StringBuilder();
BufferedReader in = null;
try {
// Twitter API endpoint
String endpoint = "https://api.twitter.com/2/users/"+twitterId+"/liked_tweets";
// 构造带有参数的 URL
String urlWithParams = endpoint + "?expansions=edit_history_tweet_ids,referenced_tweets.id";
// 创建 URL 对象
URL url = new URL(urlWithParams);
URLConnection connection = url.openConnection();
connection.setRequestProperty("Authorization", "Bearer " + token);
connection.setRequestProperty("Content-Type","application/json");
connection.connect();
in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
while ((line = in.readLine()) != null)
{
result.append(line);
}
List<String> list = new ArrayList<>();
JSONObject json = JSONObject.parseObject(result.toString());
JSONArray twittList = json.getJSONArray("data");
if(twittList != null && twittList.size() > 0){
for (int i = 0; i < twittList.size(); i++) {
JSONObject twitt = twittList.getJSONObject(i);
list.add(twitt.getString("id"));
}
return list;
}
return null;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 根据推文ID查询那些用户进行了点赞
* @param tweetId
* @return
*/
public List<TransshipmentUserDto> thumbsUpList(String tweetId){
CommonsHttpOAuthConsumer consumer = new CommonsHttpOAuthConsumer(TwitterConfig.CONSUMER_KEY, TwitterConfig.CONSUMER_SECRET);
consumer.setTokenWithSecret(TwitterConfig.ACCESS_TOKEN, TwitterConfig.ACCESS_TOKEN_SECRET);
// 创建HttpClient对象
HttpClient httpClient = this.setProxy();
// 创建API请求例如获取用户的时间线
try {
URIBuilder uriBuilder = new URIBuilder("https://api.twitter.com/2/tweets/"+tweetId+"/liking_users");
HttpGet request = new HttpGet(uriBuilder.build());
request.setHeader("Content-Type","application/json");
consumer.sign(request);
// 创建参数列表
HttpResponse response = httpClient.execute(request);
// 处理API响应
int statusCode = response.getStatusLine().getStatusCode();
String responseBody = EntityUtils.toString(response.getEntity());
if (statusCode == HttpURLConnection.HTTP_OK) {
// 读取响应
//默认最大返回100条
JSONObject array = JSONObject.parseObject(responseBody);
JSONArray arr = array.getJSONArray("data");
List<TransshipmentUserDto> list = new ArrayList<>();
for (int i = 0; i < arr.size(); i++) {
list.add(arr.getObject(i,TransshipmentUserDto.class));
}
// 打印响应
return list;
} else {
System.out.println("Failed to fetch data from Twitter API. Response code: " + statusCode);
}
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
}catch (IOException e) {
e.printStackTrace();
}
return null;
}
public void bindUser(String id) {
Integer num = dslContext.selectCount().from(T_MEMBER).where(T_MEMBER.TWITTER_ID.eq(id)).fetchAnyInto(Integer.class);
Assert.isTrue(num == 0,"The account has been linked Twitter");
}
/**
* 查询我的推文列表
* @param tweetUserId
* @param token
* @param ttTweetsId 平台指定转推文的ID
* @param maxResults = 5-10之间
* @return
public Integer getTweetList(String tweetUserId,String token,Integer maxResults,String ttTweetsId){
try {
String httpUrl = "https://api.twitter.com/2/users/"+ tweetUserId + "/tweets?max_results="+maxResults;
httpUrl += "&expansions=author_id,edit_history_tweet_ids,referenced_tweets.id&tweet.fields=created_at";
// 只查用户当日的推文
Instant currentTime = LocalDateTime.of(LocalDate.now(), LocalTime.MIN).toInstant(ZoneOffset.of("+8"));
DateTimeFormatter formatter = DateTimeFormatter.ISO_INSTANT;
String endTimeRFC3339 = formatter.format(currentTime);
httpUrl += "&start_time="+endTimeRFC3339;
// 构建请求 URL
URL url = new URL(httpUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法和请求头
connection.setRequestMethod("GET");
connection.setRequestProperty("Authorization", "Bearer " + token);
// 发送请求
int responseCode = connection.getResponseCode();
Assert.isTrue(responseCode == HttpURLConnection.HTTP_OK, "get tweet error");
Integer numer = 0;
// 读取响应
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
JSONObject jsonObject = JSON.parseObject(response.toString());
JSONArray jsonArray = (JSONArray) jsonObject.get("data");
if(jsonArray == null){
return numer;
}
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject json = jsonArray.getJSONObject(i);
JSONArray referencedTweets = json.getJSONArray("referenced_tweets");
if(referencedTweets != null){
retweeted: 表示当前推文是转推Retweet的引用
quoted: 表示当前推文是引用推文Quote Tweet的引用
replied_to: 表示当前推文是回复Reply的引用
//上个推文的id
String type = referencedTweets.getJSONObject(0).get("type").toString();
String id = referencedTweets.getJSONObject(0).get("id").toString();
if(type.equals("quoted") || type.equals("retweeted") && ttTweetsId.equals(id)){
//quoted 表示推文是引用
numer++;
}
}
}
// 打印响应
return numer;
} catch (IOException e) {
e.printStackTrace();
}
return 0;
}*/
/*private String getFollowers(String url_with_cursor) {
String tweetResponse = null;
HttpClient httpClient = HttpClients.custom()
.setDefaultRequestConfig(RequestConfig.custom()
.setCookieSpec(CookieSpecs.STANDARD).build())
.build();
try {
URIBuilder uriBuilder = new URIBuilder(url_with_cursor);
ArrayList<NameValuePair> queryParameters = new ArrayList<>();
queryParameters.add(new BasicNameValuePair("user.fields", "username"));
uriBuilder.addParameters(queryParameters);
HttpGet httpGet = new HttpGet(uriBuilder.build());
httpGet.setHeader("Authorization", String.format("Bearer %s", "T2xwaGZOazRBbW9USWluSmpueUIwNW51MXhGa1dzWkpWTkgzOFJCdTRyRHNlOjE3MTAzMTk0MDM4NDU6MToxOmF0OjE"));
httpGet.setHeader("Content-Type", "application/json");
HttpResponse response = httpClient.execute(httpGet);
HttpEntity entity = response.getEntity();
if (null != entity) {
tweetResponse = EntityUtils.toString(entity, "UTF-8");
}
} catch (Exception e) {
e.printStackTrace();
}
return tweetResponse;
}*/
/**
* 查询用户推文列表
* @param setCodeNo
* @return
public TgUserReq findChannelMember(AttentionReq setCodeNo) {
String tweetNumber = "tweet_list"+setCodeNo.getAddress();
String value = RedisUtil.get(tweetNumber);
if(value != null){
return new TgUserReq().setTwitterNumber(Integer.parseInt(value));
}
String userId = RedisUtil.get("twitter_user"+setCodeNo.getAddress());
String tokenKey = RedisUtil.get("twitter_token" + setCodeNo.getAddress());
MerchantPojo merchantPojo = merchantService.getMerchant(setCodeNo.getCodeNo(),setCodeNo.getMerchantOn());
MerchantConfigPojo merchantConfigPojo = merchantService.getMerchantConfig(merchantPojo.getId());
Integer num = this.getTweetList(userId,tokenKey,100,merchantConfigPojo.getTtTweetsId());
if(num > 0){
TaskLogRecord memberRecord = dslContext.selectFrom(TASK_LOG).where(TASK_LOG.STATUS.eq(1).and(TASK_LOG.ADDRESS.eq(setCodeNo.getAddress()))
.and(TASK_LOG.TASK_TYPE.eq(1))
.and(TASK_LOG.CREATE_TIME.between(new Timestamp(com.ruoyi.common.utils.DateUtils.getStartDate(new Date()).getTime()),new Timestamp(com.ruoyi.common.utils.DateUtils.getFinallyDate(new Date()).getTime())))).fetchAny();
if(memberRecord != null){
memberRecord.setTaskType(3);
memberRecord.store();
}
}
RedisUtil.setEx(tweetNumber,num.toString(),60 * 5);
return new TgUserReq().setTwitterNumber(num);
}*/
}

View File

@ -0,0 +1,178 @@
package com.alive.server.service;
import com.alive.commons.config.BaseComponent;
import com.alive.commons.enums.WalletLogTypeEnum;
import com.alive.commons.util.CoinUtil;
import com.alive.db.jooq.tables.records.ActivityStatisticsRecord;
import com.alive.db.jooq.tables.records.CoinConfigRecord;
import com.alive.db.jooq.tables.records.TMemberWalletRecord;
import com.alive.server.dto.WalletOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import static com.alive.db.jooq.Tables.*;
@Slf4j
@Service
public class WalletService extends BaseComponent {
@Autowired
private WalletService walletService;
public void initWallet(int memberId,String address) {
//实例化用户资产统计
ActivityStatisticsRecord statisticsRecord = dslContext.newRecord(ACTIVITY_STATISTICS);
statisticsRecord.setAddress(address);
statisticsRecord.setAmount(BigDecimal.ZERO);
statisticsRecord.store();
List<CoinConfigRecord> configRecords = dslContext.select().from(COIN_CONFIG).fetchInto(CoinConfigRecord.class);
for (CoinConfigRecord configRecord : configRecords) {
TMemberWalletRecord walletRecord = dslContext.newRecord(T_MEMBER_WALLET);
walletRecord.setCoinId(configRecord.getId());
walletRecord.setBalance(BigDecimal.ZERO);
walletRecord.setMemberId(memberId);
walletRecord.store();
/*if (!env.equals("prod")) {
BigDecimal gift = BigDecimal.valueOf(10000L);
operateBalance(walletRecord.getId(), WalletLogTypeEnum.ADMIN_ADD, gift, null);
}*/
}
}
public TMemberWalletRecord getWallet(int walletId) {
TMemberWalletRecord walletRecord = dslContext.fetchOne(T_MEMBER_WALLET, T_MEMBER_WALLET.ID.eq(walletId));
return walletRecord;
}
public TMemberWalletRecord getWallet(Integer memberId, int coinId) {
if (memberId == null) {
return null;
}
TMemberWalletRecord walletRecord = dslContext.selectFrom(T_MEMBER_WALLET).where(T_MEMBER_WALLET.MEMBER_ID.eq(memberId).and(T_MEMBER_WALLET.COIN_ID.eq(coinId))).fetchAny();
if(walletRecord == null){
walletRecord = dslContext.newRecord(T_MEMBER_WALLET);
walletRecord.setCoinId(coinId);
walletRecord.setMemberId(memberId);
walletRecord.store();
}
return walletRecord;
}
public boolean operateBalance(WalletOperation op) {
return operateBalance(op.getWalletId(), op.getOpType(), op.getOpAmount(), op.getExtRemark());
}
public boolean operateBalance(Integer walletId, WalletLogTypeEnum logType, BigDecimal opValue, String extRemark) {
if (walletId == null) {
return false;
}
if (opValue.compareTo(BigDecimal.ZERO) == 0) {
return true;
}
int result = dslContext.update(T_MEMBER_WALLET)
.set(T_MEMBER_WALLET.BALANCE, T_MEMBER_WALLET.BALANCE.add(opValue))
.where(T_MEMBER_WALLET.ID.eq(walletId).and(T_MEMBER_WALLET.BALANCE.ge(opValue.negate())))
.execute();
if (result == 0) {
return false;
}
TMemberWalletRecord walletRecord = getWallet(walletId);
dslContext.insertInto(T_MEMBER_WALLET_LOG)
.set(T_MEMBER_WALLET_LOG.WALLET_ID, walletId)
.set(T_MEMBER_WALLET_LOG.MEMBER_ID, walletRecord.getMemberId())
.set(T_MEMBER_WALLET_LOG.TYPE, 1)
.set(T_MEMBER_WALLET_LOG.COIN_ID, walletRecord.getCoinId())
.set(T_MEMBER_WALLET_LOG.OP_VALUE, opValue)
.set(T_MEMBER_WALLET_LOG.OP_BEFORE, walletRecord.getBalance().subtract(opValue))
.set(T_MEMBER_WALLET_LOG.OP_AFTER, walletRecord.getBalance())
.set(T_MEMBER_WALLET_LOG.OP_TYPE, logType.getCode())
.set(T_MEMBER_WALLET_LOG.OP_REMARK, logType.getRemark())
.set(T_MEMBER_WALLET_LOG.EXT_REMARK, extRemark != null ? extRemark : "")
.execute();
return true;
}
public boolean operateFrozen(WalletOperation op) {
return operateFrozen(op.getWalletId(), op.getOpType(), op.getOpAmount(), op.getExtRemark());
}
public boolean operateFrozen(Integer walletId, WalletLogTypeEnum logType, BigDecimal opValue, String extRemark) {
if (walletId == null) {
return false;
}
if (opValue.compareTo(BigDecimal.ZERO) == 0) {
return true;
}
int result = dslContext.update(T_MEMBER_WALLET)
.set(T_MEMBER_WALLET.FROZEN, T_MEMBER_WALLET.FROZEN.add(opValue))
.where(T_MEMBER_WALLET.ID.eq(walletId).and(T_MEMBER_WALLET.FROZEN.ge(opValue.negate())))
.execute();
if (result == 0) {
return false;
}
TMemberWalletRecord walletRecord = getWallet(walletId);
dslContext.insertInto(T_MEMBER_WALLET_LOG)
.set(T_MEMBER_WALLET_LOG.WALLET_ID, walletId)
.set(T_MEMBER_WALLET_LOG.MEMBER_ID, walletRecord.getMemberId())
.set(T_MEMBER_WALLET_LOG.TYPE, 2)
.set(T_MEMBER_WALLET_LOG.COIN_ID, walletRecord.getCoinId())
.set(T_MEMBER_WALLET_LOG.OP_VALUE, opValue)
.set(T_MEMBER_WALLET_LOG.OP_BEFORE, walletRecord.getFrozen().subtract(opValue))
.set(T_MEMBER_WALLET_LOG.OP_AFTER, walletRecord.getFrozen())
.set(T_MEMBER_WALLET_LOG.OP_TYPE, logType.getCode())
.set(T_MEMBER_WALLET_LOG.OP_REMARK, logType.getRemark())
.set(T_MEMBER_WALLET_LOG.EXT_REMARK, extRemark != null ? extRemark : "")
.execute();
return true;
}
public boolean batchOperate(List<WalletOperation> operations) {
return batchOperate(operations, true);
}
public boolean batchOperate(List<WalletOperation> operations, boolean check) {
return batchOperate(operations, check, true);
}
public boolean batchOperate(List<WalletOperation> operations, boolean check, boolean sort) {
if (sort) {
operations.sort(Comparator.comparingInt(WalletOperation::getWalletId));
}
for (WalletOperation item : operations) {
boolean res = false;
switch (item.getType()) {
case 1:
res = operateBalance(item);
break;
case 2:
res = operateFrozen(item);
break;
default:
log.warn("bad wallet operate type");
}
if (!res && check) {
log.error("批量操作失败");
return false;
}
}
return true;
}
public void verifyActivityStatisticsRecord(String account) {
Integer count = dslContext.selectCount().from(ACTIVITY_STATISTICS).where(ACTIVITY_STATISTICS.ADDRESS.eq(account)).fetchAnyInto(Integer.class);
if(count == null || count == 0){
//实例化用户资产统计
ActivityStatisticsRecord statisticsRecord = dslContext.newRecord(ACTIVITY_STATISTICS);
statisticsRecord.setAddress(account);
statisticsRecord.setAmount(BigDecimal.ZERO);
statisticsRecord.store();
}
}
}

View File

@ -0,0 +1,64 @@
package com.alive.server.task;
import com.alive.server.service.TaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
/**
* 活动定时任务
*/
@Slf4j
@Component
@Transactional(isolation = Isolation.READ_COMMITTED)
public class ActivityTask {
@Autowired
private TaskService taskService;
/**
* 5分钟执行一次 关注改名
*/
/*@Scheduled(initialDelay = 20_000, fixedDelay = 600_00 * 2)
public void twitterOptimismExec() {
taskService.optimismExec();
}*/
/**
* 5分钟执行一次 转载点赞
*/
/*@Scheduled(initialDelay = 20_000, fixedDelay = 600_00 * 2)
public void twitterActiveExec() {
taskService.activeExec();
}*/
/**
* 5分钟执行一次 加入Discord
*/
/*@Scheduled(initialDelay = 20_000, fixedDelay = 600_00 * 2)
public void addDiscord() {
taskService.addDiscord();
}*/
/**
* 5分钟执行一次 加入TG
*/
/*@Scheduled(initialDelay = 20_000, fixedDelay = 600_00 * 2)
public void addTg() {
taskService.addTg();
}*/
/**
* 10分钟执行一次 乐观验证任务
*/
/*@Scheduled(initialDelay = 20_000, fixedDelay = 600_00 * 2)
public void optimisticValidation() {
taskService.optimisticValidation();
}*/
}

View File

@ -0,0 +1,46 @@
package com.alive.server.task;
import com.alive.server.service.CrowdfundingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
/**
* 众筹
*/
@Slf4j
@Component
/*@Profile({"dev"})*/
@Transactional(isolation = Isolation.READ_COMMITTED)
public class CrowdfundingTask {
@Autowired
private CrowdfundingService crowdfundingService;
/**
* 节点交易确认 10分钟执行一次
*/
@Scheduled(initialDelay = 15_000, fixedDelay = 1000 * 60 * 10)
public void exec() {
crowdfundingService.exec();
}
/**
* 众筹监听
* socket监听区块socket同步日志监听最新的数据
* 10分钟重启一次防止异常停止监听
* @throws InterruptedException
*/
@Scheduled(initialDelay = 15 * 1000, fixedDelay = 10 * 1000)
public void bscScanTaskWithWs(){
crowdfundingService.bscScanTask();
}
}

View File

@ -0,0 +1,31 @@
package com.alive.server.task;
import com.alive.server.service.OnChainTransfersService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* 活动定时任务 链上转账
*/
@Slf4j
@Component
public class TransferTask {
@Autowired
private OnChainTransfersService onChainTransfersService;
/**
* 5分钟执行一次 链上转账
*/
@Scheduled(initialDelay = 20_000, fixedDelay = 600_00 * 2)
public void exec() {
//onChainTransfersService.transfer();
}
}

View File

@ -0,0 +1,42 @@
package com.alive.server.task;
import com.alive.server.service.BscTimingService;
import com.alive.server.service.BtcBuyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @author HayDen
*/
@Slf4j
@Component
public class WsBscScanTask {
@Autowired
private BscTimingService bscScanTask;
@Autowired
private BtcBuyService btcBuyService;
/**
* 节点交易确认 10分钟执行一次
*/
@Scheduled(initialDelay = 15_000, fixedDelay = 1000 * 60 * 10)
public void btcTransactionConfirmation() {
//btcBuyService.exec();
}
/**
* socket监听区块socket同步日志监听最新的数据
* 10分钟重启一次防止异常停止监听
* @throws InterruptedException
*/
@Scheduled(initialDelay = 15 * 1000, fixedDelay = 6 * 1000)
public void bscScanTaskWithWs(){
//bscScanTask.bscScanTask();
}
}

View File

@ -0,0 +1,67 @@
package com.alive.server.task;
import com.alive.server.service.BscWsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.http.HttpService;
import java.util.Arrays;
import java.util.List;
/**
* @author HayDen
*/
@Slf4j
@Component
public class WsCrossBridgesScanTask {
/**
* socket节点
*/
@Value("${com.alive.roosChainWsUrl}")
private String roosChainWsUrl;
/**
* 合约地址
*/
@Value("${com.alive.roosContractUrl}")
private String roosContractUrl;
@Autowired
private BscWsService bscWsService;
public Web3j getCrossBridgesBscWsWeb3j() {
return Web3j.build(new HttpService(roosChainWsUrl));
}
/**
* 需要同步日志的合约
* @return
*/
private List<String> getAddresses() {
return Arrays.asList(roosContractUrl);
}
/**
* 验证跨连桥任务数据
* 10分钟重启一次防止异常停止监听
* @throws InterruptedException
*/
@Scheduled(initialDelay = 15 * 1000, fixedDelay = 60 * 1000 * 10)
public void crossBridgesBscScanTaskWithWs(){
/* long threadId = Thread.currentThread().getId();
log.info("enter {}", threadId);
EthFilter filter = new EthFilter(
DefaultBlockParameter.valueOf("latest"),
DefaultBlockParameter.valueOf("latest"),
this.getAddresses()
);
Flowable<Log> flowable = this.getCrossBridgesBscWsWeb3j().ethLogFlowable(filter);
bscWsService.wsExec(flowable);*/
}
}

View File

@ -0,0 +1,10 @@
package com.alive.server.web3;
import org.web3j.protocol.core.methods.response.EthLog;
import java.util.List;
public interface ContractEventHandle {
String handle(EthLog.LogObject logObject, List<String> dataList);
}

View File

@ -0,0 +1,43 @@
package com.alive.server.web3;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Objects;
public class RLPEncryption {
private static final String AES_ALGORITHM = "AES";
public static byte[] encrypt(byte[] key, byte[] data) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES_ALGORITHM);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
return cipher.doFinal(data);
}
public static byte[] decrypt(byte[] key, byte[] encryptedData) throws Exception {
SecretKeySpec secretKeySpec = new SecretKeySpec(key, AES_ALGORITHM);
Cipher cipher = Cipher.getInstance(AES_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
return cipher.doFinal(encryptedData);
}
public static SecretKey generateAESKey(int keySize) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(keySize);
return keyGenerator.generateKey();
}
public static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
}

View File

@ -0,0 +1,34 @@
package com.alive.server.web3;
import java.security.*;
import javax.crypto.Cipher;
public class RSAEncryption {
public static void main(String[] args) throws Exception {
// 要加密的明文
String plainText = "Hello, World!";
// 1. 生成 RSA 密钥对
KeyPair keyPair = generateRSAKeyPair();
PublicKey publicKey = keyPair.getPublic();
// 2. 使用 Solidity 合约提供的公钥加密数据
byte[] encryptedData = encryptData(publicKey, plainText.getBytes());
System.out.println("Encrypted data: " + new String(encryptedData));
// 将加密后的数据发送到 Solidity 合约
}
public static KeyPair generateRSAKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048);
return keyPairGenerator.generateKeyPair();
}
public static byte[] encryptData(PublicKey publicKey, byte[] data) throws Exception {
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
return cipher.doFinal(data);
}
}

View File

@ -0,0 +1,193 @@
package com.alive.server.web3;
import com.alive.db.entity.Vo.PayCoinVo;
import com.alive.db.entity.Vo.TransactionDataVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.web3j.protocol.Web3j;
import org.web3j.protocol.core.methods.response.EthGetTransactionReceipt;
import org.web3j.protocol.core.methods.response.Log;
import org.web3j.protocol.core.methods.response.TransactionReceipt;
import org.web3j.protocol.http.HttpService;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
@Slf4j
@Service
public class Web3jServer {
/**
* 普通节点
*/
@Value("${com.alive.chainUrl}")
private String chainUrl;
public Web3j getWeb3j(){
return Web3j.build(new HttpService(chainUrl));
}
/**
* 通过hash获取交易的数据
* @param hash
* @return
*/
public TransactionDataVo getEthLogsByHash(String hash) throws IOException {
TransactionDataVo vo = new TransactionDataVo();
EthGetTransactionReceipt transaction = this.getWeb3j().ethGetTransactionReceipt(hash).send();
TransactionReceipt transactionReceipt = transaction.getResult();
if(transactionReceipt == null){
return new TransactionDataVo().setStatus(-1);
}
//0=失败 1=成功
String status = typeCast16By10(transactionReceipt.getStatus());
vo.setStatus(Integer.parseInt(status));
if(!status.equals("1")){
return vo;
}
vo.setFrom(transactionReceipt.getFrom().toLowerCase());
List<Log> log = transactionReceipt.getLogs();
if(log == null || log.size() == 0){
return null;
}
//交易数据
Log payLogs = log.get(0);
vo.setPayAmount(new BigDecimal(typeCast16By10(payLogs.getData())));
vo.setNftNumber(0);
vo.setNftIds(new ArrayList<>());
Integer lenth = log.size();
for (int i = 0; i < lenth; i++) {
List<String> topics = log.get(i).getTopics();
if(topics.size() != 4 && vo.getNftIds().size() > 0){
break;
}
if(topics.size() == 4){
vo.setNftNumber(vo.getNftNumber() + 1);
vo.getNftIds().add(Integer.parseInt(typeCast16By10(topics.get(3))));
}
}
//取出上级地址
payLogs = log.get(lenth - 2);
if(payLogs.getTopics().size() != 3){
payLogs = log.get(lenth - 3);
}
if(payLogs.getTopics().size() != 3){
//没有上级
vo.setTeamAmount(BigDecimal.ZERO);
vo.setTeamAddress("0");
}else{
BigDecimal teamAmount = new BigDecimal(typeCast16By10(payLogs.getData()));
vo.setTeamAmount(teamAmount);
vo.setTeamAddress("0x"+payLogs.getTopics().get(2).substring(26,payLogs.getTopics().get(2).length()));
}
return vo;
}
/**
* 通过hash获取交易的数据
* @param hash
* @return
*/
public PayCoinVo crowdfundingByHash(String hash) throws IOException {
PayCoinVo vo = new PayCoinVo();
vo.setUsdtAmount(BigDecimal.ZERO);
EthGetTransactionReceipt transaction = this.getWeb3j().ethGetTransactionReceipt(hash).send();
TransactionReceipt transactionReceipt = transaction.getResult();
if(transactionReceipt == null){
return new PayCoinVo().setStatus(-1);
}
//0=失败 1=成功
String status = typeCast16By10(transactionReceipt.getStatus());
vo.setStatus(Integer.parseInt(status));
if(!status.equals("1")){
return vo;
}
vo.setAddress(transactionReceipt.getFrom().toLowerCase());
List<Log> log = transactionReceipt.getLogs();
if(log == null || log.size() == 0){
return null;
}
//交易数据
Log payLogs = log.get(0);
vo.setUsdtAmount(new BigDecimal(typeCast16By10(payLogs.getData())));
payLogs = log.get(1);
Integer len = payLogs.getData().length();
vo.setOrderNumber(getValue(payLogs.getData().substring(len-64,len),0,false));
return vo;
}
/**
* 查询日志里面加indexed的内容
* @param value 转换的内容
* @return 16进制转换成10进制
*/
public static String typeCast16By10(String value){
String ret = value.substring(2,value.length());
if(StringUtils.isBlank(ret)){
return "0";
}
//16进制转10进制
return new BigInteger(ret, 16).toString();
}
/**
* 将ETH地址转换成uint160
* @param ethAddress
* @return
*/
public static BigInteger addressToUint160(String ethAddress){
// 将地址转换为 BigInteger
BigInteger addressAsBigInt = new BigInteger(ethAddress.substring(2), 16);
// Solidity 中的 uint160 最大值
BigInteger uint160MaxValue = new BigInteger("ffffffffffffffffffffffffffffffffffffffff", 16);
// 取地址的低 160 位作为 Solidity 中的 uint160
BigInteger uint160Address = addressAsBigInt.and(uint160MaxValue);
return uint160Address;
}
/**
* 查询日志里面加indexed的内容
* @param topList 日志内容
* @param code 查询第几个
* @return
*/
public static BigInteger getNmber(List<String> topList, Integer code){
String ret = topList.get(code);
ret = ret.substring(2,ret.length());
//16进制转10进制
return new BigInteger(ret, 16);
}
/**
* 获取没有加indexed的内容
* @param date 拆分的参数
* @param code 取的位数
* @param address 是否返回地址
* @return
*/
public static String getValue(String date, Integer code, Boolean address){
int number = 64;
if(code == 0){
date = date.substring(0,number);
}else{
code = number * code;
date = date.substring(code,code+number);
}
if(address){
return "0x"+date.substring(24,date.length());
}else{
return new BigInteger(date, 16).toString();
}
}
}

View File

@ -0,0 +1,44 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/alive_dev?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&allowMultiQueries=true
username: root
password: root
redis:
host: 127.0.0.1
database: 2
password:
lettuce:
pool:
max-active: 20
max-idle: 16
max-wait: 1000ms
min-idle: 10
com.alive:
#ARB节点服务器
chainUrl: 'https://go.getblock.io/7a508279a1a84ba6832cbc53f27e571a/'
#ARBsocket节点服务器
chainWsUrl: 'https://go.getblock.io/7a508279a1a84ba6832cbc53f27e571a/'
contractUrl: '0x9B20e2e0b114D50B3a8328e7Ca8C1303aFDC13A4'
#任务测试跨连桥合约监听器
roosChainWsUrl: 'https://go.getblock.io/8181dc29e53a4ea4948e30c61e3e0aeb/'
roosContractUrl: '0xeeEC77da95C788b58595Fcd7eBad1d87Ae821aCE'
common:
auth:
jwtSecret: 'inode-dev'
task:
enable: true
bot: true
cron:
sampleCronTask: '0 */10 * * * ?' # 示例cron任务
#链上转账配置
chain:
transfer:
rpcUrl: 'https://testrpc.roospro.com'
erc20: '0x204074AD198E7c6e79E195DAf576bc7D53967B45'
privateKey: 'd94f3dc1629be0bb718ad9bb55d09d57de1667258101565f58d99018bdfba029'

View File

@ -0,0 +1,44 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/alive_prod?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&allowMultiQueries=true
username: alive_prod
password: 6jD2S3CGwGYhRXNp
redis:
host: 127.0.0.1
database: 7
password:
lettuce:
pool:
max-active: 20
max-idle: 16
max-wait: 1000ms
min-idle: 10
com.alive:
#ARB节点服务器
chainUrl: 'https://go.getblock.io/e3842ff6182b4907ac9863503e77744e/'
#ARBsocket节点服务器
chainWsUrl: 'https://go.getblock.io/e3842ff6182b4907ac9863503e77744e/'
contractUrl: '0x92B64f3BCf327ada976Fa876c7F17b177f333Eea'
#任务测试跨连桥合约监听器 暂时没有用到
roosChainWsUrl: 'https://go.getblock.io/8181dc29e53a4ea4948e30c61e3e0aeb/'
roosContractUrl: '0xeeEC77da95C788b58595Fcd7eBad1d87Ae821aCE'
common:
auth:
jwtSecret: 'inode-dev'
task:
enable: true
bot: true
cron:
sampleCronTask: '0 */10 * * * ?' # 示例cron任务
#链上转账配置
chain:
transfer:
rpcUrl: 'https://testrpc.roospro.com'
erc20: '0x204074AD198E7c6e79E195DAf576bc7D53967B45'
privateKey: 'd94f3dc1629be0bb718ad9bb55d09d57de1667258101565f58d99018bdfba029'

View File

@ -0,0 +1,44 @@
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/alive_test?useSSL=false&useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&allowMultiQueries=true
username: alive_test
password: cf2xrRTPHL875NRA
redis:
host: 127.0.0.1
database: 2
password:
lettuce:
pool:
max-active: 20
max-idle: 16
max-wait: 1000ms
min-idle: 10
com.alive:
#ARB节点服务器
chainUrl: 'https://go.getblock.io/7a508279a1a84ba6832cbc53f27e571a/'
#ARBsocket节点服务器
chainWsUrl: 'https://go.getblock.io/7a508279a1a84ba6832cbc53f27e571a/'
contractUrl: '0x9B20e2e0b114D50B3a8328e7Ca8C1303aFDC13A4'
#任务测试跨连桥合约监听器
roosChainWsUrl: 'https://go.getblock.io/8181dc29e53a4ea4948e30c61e3e0aeb/'
roosContractUrl: '0xeeEC77da95C788b58595Fcd7eBad1d87Ae821aCE'
common:
auth:
jwtSecret: 'inode-dev'
task:
enable: true
bot: true
cron:
sampleCronTask: '0 */10 * * * ?' # 示例cron任务
#链上转账配置
chain:
transfer:
rpcUrl: 'https://testrpc.roospro.com'
erc20: '0x204074AD198E7c6e79E195DAf576bc7D53967B45'
privateKey: 'd94f3dc1629be0bb718ad9bb55d09d57de1667258101565f58d99018bdfba029'

View File

@ -0,0 +1,45 @@
server:
port: 8181
shutdown: graceful
servlet:
encoding:
force: true
charset: UTF-8
spring:
profiles:
active: prod
application:
name: inode-api
jackson:
serialization: # 返回时间戳
write-dates-as-timestamps: true
servlet:
multipart:
max-file-size: 50MB
max-request-size: 50MB
logging:
level:
root: warn
com.alive: info
com.alive:
upload:
filePath: '/data/upload'
defaultUrlPreFix: 'http://file.alive.com/upload/'
config:
tokenHeader: 'Authorization'
tokenRedisKeyFormat: 'smt:token:%d:%s'
tokenExpireSeconds: 25920000
limitLoginOneOnly: false
file-provider:
ribbon:
listOfServers: http://adjjw.jiujiwang.com.cn/
ConnectTimeout: 6000
ReadTimeout: 6000

View File

@ -0,0 +1,36 @@
ResultCodeEnum.0 = Request Successful
ResultCodeEnum.400 = Request Failed
ResultCodeEnum.401 = Login Required
ResultCodeEnum.402 = Access Denied
ResultCodeEnum.500 = Network Exception
WalletLogTypeEnum.0 = System Operation
WalletLogTypeEnum.1 = System Recharge
WalletLogTypeEnum.2 = System Deduction
WalletLogTypeEnum.3 = Registration Gift
WalletLogTypeEnum.4 = Withdrawal
WalletLogTypeEnum.5 = Withdrawal Fee
WalletLogTypeEnum.6 = Withdrawal Rejected
WalletLogTypeEnum.7 = Transferred to {0}
WalletLogTypeEnum.8 = Transferred from {0}
WalletLogTypeEnum.9 = Exchanged Out
WalletLogTypeEnum.10 = Exchanged In
WalletLogTypeEnum.11 = Purchase Goods
WalletLogTypeEnum.12 = Shopping Gift
WalletLogTypeEnum.13 = Shopping Reward
WalletLogTypeEnum.14 = Sign In
WalletLogTypeEnum.15 = Sign In Reward
WalletLogTypeEnum.16 = Daily Release
WalletLogTypeEnum.17 = Team Reward
WalletLogTypeEnum.18 = Cancel Order
WalletLogTypeEnum.19 = Lucky Draw
WalletLogTypeEnum.20 = Accelerated Release
WalletLogTypeEnum.21 = Transfer Out
WalletLogTypeEnum.22 = Transfer In
WalletLogTypeEnum.23 = Static Release
WalletLogTypeEnum.24 = Accelerated Release
WalletLogTypeEnum.25 = Reservation of Equity Token
WalletLogTypeEnum.26 = Pre-purchase Success
WalletLogTypeEnum.27 = Pre-purchase Refund
WalletLogTypeEnum.28 = Participate in Sale
WalletLogTypeEnum.29 = Startup Investment Thaw

211
alive-commons/pom.xml Normal file
View File

@ -0,0 +1,211 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alive</groupId>
<artifactId>alive-api-server</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>alive-commons</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jooq</artifactId>
</dependency>
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>2.2.3.RELEASE</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form</artifactId>
<version>3.8.0</version>
</dependency>
<dependency>
<groupId>io.github.openfeign.form</groupId>
<artifactId>feign-form-spring</artifactId>
<version>3.8.0</version>
</dependency>
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.9.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.5.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.7</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.70</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.8.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>3.8.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.web3j</groupId>
<artifactId>core</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.0.18.Final</version>
</dependency>
<!-- excel -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.13</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.13</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.3.0</version>
</dependency>
<dependency>
<groupId>com.aliyun</groupId>
<artifactId>dysmsapi20170525</artifactId>
<version>2.0.22</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,64 @@
package com.alive.commons;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;
@Component
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
private static ApplicationContext applicationContext = null;
/**
* 取得存储在静态变量中的ApplicationContext.
*/
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
@SuppressWarnings("unchecked")
public static <T> T getBean(String name) {
return (T) applicationContext.getBean(name);
}
/**
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
*/
public static <T> T getBean(Class<T> requiredType) {
return applicationContext.getBean(requiredType);
}
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
/**
* 清除SpringContextHolder中的ApplicationContext为Null.
*/
public static void clearHolder() {
applicationContext = null;
}
/**
* 实现ApplicationContextAware接口, 注入Context到静态变量中.
*/
@Override
public void setApplicationContext(ApplicationContext appContext) {
applicationContext = appContext;
}
/**
* 实现DisposableBean接口, 在Context关闭时清理静态变量.
*/
@Override
public void destroy() {
SpringContextHolder.clearHolder();
}
}

View File

@ -0,0 +1,15 @@
package com.alive.commons.annotation;
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface BusinessLog {
/**
* 业务的名称,例如:"修改菜单"
*/
String value() default "";
boolean skipLogParam() default false;
}

View File

@ -0,0 +1,18 @@
package com.alive.commons.annotation;
import java.lang.annotation.*;
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Login {
//该接口是否加密
boolean encrypted() default false;
//AES解密密钥在encrypted为true时有效若不指定则从当前token中获取
String key() default "";
//权限
String[] permits() default {};
}

Some files were not shown because too many files have changed in this diff Show More