package com.izouma.nineth.service; import com.github.kevinsawicki.http.HttpRequest; import com.izouma.nineth.domain.*; import com.izouma.nineth.dto.NFT; import com.izouma.nineth.dto.NFTAccount; import com.izouma.nineth.dto.PageQuery; import com.izouma.nineth.enums.AssetStatus; import com.izouma.nineth.enums.CollectionSource; import com.izouma.nineth.enums.CollectionType; import com.izouma.nineth.event.CreateAssetEvent; import com.izouma.nineth.exception.BusinessException; import com.izouma.nineth.repo.*; import com.izouma.nineth.utils.JpaUtils; import com.izouma.nineth.utils.SecurityUtils; import io.ipfs.api.IPFS; import io.ipfs.api.MerkleNode; import io.ipfs.api.NamedStreamable; import io.ipfs.multihash.Multihash; import lombok.AllArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationContext; import org.springframework.data.domain.Page; import org.springframework.retry.annotation.Backoff; import org.springframework.retry.annotation.Retryable; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import java.io.File; import java.math.BigDecimal; import java.time.LocalDateTime; @Service @AllArgsConstructor @Slf4j public class AssetService { private AssetRepo assetRepo; private UserRepo userRepo; private NFTService nftService; private CollectionRepo collectionRepo; private ApplicationContext applicationContext; public Page all(PageQuery pageQuery) { return assetRepo.findAll(JpaUtils.toSpecification(pageQuery, Asset.class), JpaUtils.toPageRequest(pageQuery)); } @Async public void createAsset(Order order) { User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("用户不存在")); if (StringUtils.isEmpty(user.getPublicKey())) { NFTAccount account = nftService.createAccount(user.getUsername()); user.setNftAccount(account.getAccountId()); user.setKmsId(account.getAccountKmsId()); user.setPublicKey(account.getPublicKey()); userRepo.save(user); } try { NFT nft = nftService.createToken(user.getNftAccount()); String ipfsUrl = ipfsUpload(order.getPic().get(0).getUrl()); if (nft != null) { Asset asset = Asset.builder() .userId(user.getId()) .orderId(order.getId()) .collectionId(order.getCollectionId()) .minter(order.getMinter()) .minterId(order.getMinterId()) .minterAvatar(order.getMinterAvatar()) .name(order.getName()) .detail(order.getDetail()) .pic(order.getPic()) .properties(order.getProperties()) .category(order.getCategory()) .canResale(order.isCanResale()) .royalties(order.getRoyalties()) .serviceCharge(order.getServiceCharge()) .tokenId(nft.getTokenId()) .blockNumber(nft.getBlockNumber()) .txHash(nft.getTxHash()) .gasUsed(nft.getGasUsed()) .price(order.getPrice()) .status(AssetStatus.NORMAL) .ipfsUrl(ipfsUrl) .number((int) (assetRepo.countByIpfsUrlAndStatusNot(ipfsUrl, AssetStatus.TRANSFERRED) + 1)) .build(); assetRepo.save(asset); applicationContext.publishEvent(new CreateAssetEvent(this, true, order, asset)); return; } } catch (Exception e) { log.error("创建token失败", e); } applicationContext.publishEvent(new CreateAssetEvent(this, false, order, null)); } @Async public void createAsset(Order order, BlindBoxItem winItem) { User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("用户不存在")); if (StringUtils.isEmpty(user.getPublicKey())) { NFTAccount account = nftService.createAccount(user.getUsername()); user.setNftAccount(account.getAccountId()); user.setKmsId(account.getAccountKmsId()); user.setPublicKey(account.getPublicKey()); userRepo.save(user); } try { NFT nft = nftService.createToken(user.getNftAccount()); if (nft != null) { Asset asset = Asset.builder() .userId(user.getId()) .orderId(order.getId()) .collectionId(order.getCollectionId()) .minter(winItem.getMinter()) .minterId(winItem.getMinterId()) .minterAvatar(winItem.getMinterAvatar()) .name(winItem.getName()) .detail(winItem.getDetail()) .pic(winItem.getPic()) .properties(winItem.getProperties()) .canResale(winItem.isCanResale()) .royalties(winItem.getRoyalties()) .serviceCharge(winItem.getServiceCharge()) .tokenId(nft.getTokenId()) .blockNumber(nft.getBlockNumber()) .txHash(nft.getTxHash()) .gasUsed(nft.getGasUsed()) .price(order.getPrice()) .status(AssetStatus.NORMAL) .ipfsUrl(ipfsUpload(winItem.getPic().get(0).getUrl())) .build(); assetRepo.save(asset); applicationContext.publishEvent(new CreateAssetEvent(this, true, order, asset)); return; } } catch (Exception e) { log.error("创建token失败", e); } applicationContext.publishEvent(new CreateAssetEvent(this, false, order, null)); } public String ipfsUpload(String url) { try { IPFS ipfs = new IPFS("121.40.132.44", 5001); HttpRequest request = HttpRequest.get(url); File file = File.createTempFile("ipfs", ".tmp"); request.receive(file); NamedStreamable.FileWrapper file1 = new NamedStreamable.FileWrapper(file); MerkleNode put = ipfs.add(file1).get(0); Multihash multihash = ipfs.pin.add(put.hash).get(0); log.info("上传ipfs成功 {}", multihash.toBase58()); return multihash.toBase58(); } catch (Exception e) { } return null; } public void publicShow(Long id) { Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录")); if (asset.isPublicShow()) { return; } User owner = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在")); Collection collection = Collection.builder() .name(asset.getName()) .pic(asset.getPic()) .minter(asset.getMinter()) .minterId(asset.getMinterId()) .minterAvatar(asset.getMinterAvatar()) .owner(owner.getNickname()) .ownerId(owner.getId()) .ownerAvatar(owner.getAvatar()) .detail(asset.getDetail()) .type(CollectionType.DEFAULT) .source(CollectionSource.TRANSFER) .sale(0) .stock(1) .total(1) .onShelf(true) .salable(false) .price(BigDecimal.valueOf(0)) .properties(asset.getProperties()) .canResale(asset.isCanResale()) .royalties(asset.getRoyalties()) .serviceCharge(asset.getServiceCharge()) .assetId(id) .build(); collectionRepo.save(collection); asset.setPublicShow(true); asset.setPublicCollectionId(collection.getId()); assetRepo.save(asset); } public void Consignment(Long id, BigDecimal price) { Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录")); Collection collection = null; if (asset.isPublicShow() && asset.getCollectionId() != null) { collection = collectionRepo.findById(asset.getCollectionId()).orElse(null); } User owner = userRepo.findById(asset.getUserId()).orElseThrow(new BusinessException("用户不存在")); if (collection == null) { collection = Collection.builder() .name(asset.getName()) .pic(asset.getPic()) .minter(asset.getMinter()) .minterId(asset.getMinterId()) .minterAvatar(asset.getMinterAvatar()) .owner(owner.getNickname()) .ownerId(owner.getId()) .ownerAvatar(owner.getAvatar()) .detail(asset.getDetail()) .type(CollectionType.DEFAULT) .source(CollectionSource.TRANSFER) .sale(0) .stock(1) .total(1) .onShelf(true) .salable(false) .price(BigDecimal.valueOf(0)) .properties(asset.getProperties()) .canResale(asset.isCanResale()) .royalties(asset.getRoyalties()) .serviceCharge(asset.getServiceCharge()) .assetId(id) .build(); } collection.setSalable(true); collection.setPrice(price); collectionRepo.save(collection); asset.setPublicShow(true); asset.setPublicCollectionId(collection.getId()); assetRepo.save(asset); } public void cancelPublic(Long id) { Asset asset = assetRepo.findById(id).orElseThrow(new BusinessException("无记录")); if (!asset.isPublicShow()) { return; } Collection collection = collectionRepo.findById(asset.getPublicCollectionId()) .orElseThrow(new BusinessException("无展示记录")); collectionRepo.delete(collection); asset.setPublicShow(false); asset.setCollectionId(null); assetRepo.save(asset); } public void usePrivilege(Long assetId, Long privilegeId) { Asset asset = assetRepo.findById(assetId).orElseThrow(new BusinessException("无记录")); asset.getPrivileges().stream().filter(p -> p.getId().equals(privilegeId)).forEach(p -> { p.setOpened(true); p.setOpenTime(LocalDateTime.now()); p.setOpenedBy(SecurityUtils.getAuthenticatedUser().getId()); }); assetRepo.save(asset); } }