chain balance query
This commit is contained in:
parent
0303dd302e
commit
e7da389340
@ -3,6 +3,8 @@ package system
|
||||
import (
|
||||
"f5"
|
||||
"fmt"
|
||||
"main/mt"
|
||||
"main/service"
|
||||
|
||||
"main/constant"
|
||||
"main/model/system"
|
||||
@ -125,3 +127,68 @@ func (this *NFTApi) NFTQuery(c *gin.Context) {
|
||||
return p
|
||||
})
|
||||
}
|
||||
|
||||
func (this *NFTApi) BalanceQuery(c *gin.Context) {
|
||||
type BalanceQueryForm struct {
|
||||
Account string `json:"account_address"`
|
||||
}
|
||||
|
||||
reqJson := BalanceQueryForm{}
|
||||
if !checkparam(&reqJson, c) {
|
||||
return
|
||||
}
|
||||
|
||||
selfaccount := false
|
||||
if reqJson.Account != "" {
|
||||
mt.Table.Chain.Traverse(func(item *mt.Chain) bool {
|
||||
if item.GetAccountAddress() == reqJson.Account {
|
||||
selfaccount = true
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
type retitem struct {
|
||||
Account string `json:"account_address"`
|
||||
TokenName string `json:"token_name"`
|
||||
ChainBalance string `json:"chain_balance"`
|
||||
Recharge int64 `json:"recharge"`
|
||||
NetId int32 `json:"net_id"`
|
||||
TokenAddress string `json:"-"`
|
||||
}
|
||||
result := []retitem{}
|
||||
|
||||
mt.Table.Chain.Traverse(func(item *mt.Chain) bool {
|
||||
account := item.GetAccountAddress()
|
||||
if selfaccount && account != reqJson.Account {
|
||||
return true
|
||||
}
|
||||
|
||||
if reqJson.Account != "" && !selfaccount {
|
||||
account = reqJson.Account
|
||||
}
|
||||
|
||||
p := q5.NewSliceElement(&result)
|
||||
p.Account = account
|
||||
p.NetId = item.GetNetId()
|
||||
p.TokenName = item.GetTokenName()
|
||||
p.TokenAddress = item.GetTokenAddress()
|
||||
|
||||
key := fmt.Sprintf("%d$%s", item.GetNetId(), item.GetTokenAddress())
|
||||
if selfaccount || reqJson.Account == "" {
|
||||
p.ChainBalance, p.Recharge = service.Balance.GetGlobalBalance(key)
|
||||
} else {
|
||||
p.ChainBalance, p.Recharge = service.Balance.GetAccoutBalance(key, account)
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 0,
|
||||
"message": "",
|
||||
"data": result,
|
||||
})
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ const (
|
||||
APP_MODULE_IDX = iota
|
||||
ROUTER_MODULE_IDX
|
||||
SESSION_MGR_MODULE_IDX
|
||||
SERVICE_MGR_MODULE_IDX
|
||||
MAX_MODULE_IDX
|
||||
)
|
||||
|
||||
|
@ -1,16 +1,17 @@
|
||||
package global
|
||||
|
||||
import (
|
||||
"q5"
|
||||
"fmt"
|
||||
"main/constant"
|
||||
"main/common"
|
||||
"main/constant"
|
||||
"q5"
|
||||
)
|
||||
|
||||
var modules [constant.MAX_MODULE_IDX]q5.Module
|
||||
var initOrders = []int32 {
|
||||
constant.ROUTER_MODULE_IDX,
|
||||
constant.SESSION_MGR_MODULE_IDX,
|
||||
constant.SERVICE_MGR_MODULE_IDX,
|
||||
}
|
||||
|
||||
var app common.App
|
||||
@ -39,6 +40,10 @@ func RegModule(idx int32, m q5.Module) {
|
||||
{
|
||||
sessionMgr = m.(common.SessionMgr)
|
||||
}
|
||||
case constant.SERVICE_MGR_MODULE_IDX:
|
||||
{
|
||||
|
||||
}
|
||||
default:
|
||||
{
|
||||
panic("unknow module")
|
||||
|
14
server/adminserver/mt/Chain.go
Normal file
14
server/adminserver/mt/Chain.go
Normal file
@ -0,0 +1,14 @@
|
||||
package mt
|
||||
|
||||
import (
|
||||
"f5"
|
||||
"main/mtb"
|
||||
)
|
||||
|
||||
type Chain struct {
|
||||
mtb.Erc20
|
||||
}
|
||||
|
||||
type ChainTable struct {
|
||||
f5.RawMetaTable[Chain]
|
||||
}
|
@ -18,6 +18,7 @@ type table struct {
|
||||
ConfDb *ConfDbTable
|
||||
Item *ItemTable
|
||||
Contract *ContractTable
|
||||
Chain *ChainTable
|
||||
}
|
||||
|
||||
var Table = f5.New(func(this *table) {
|
||||
@ -78,4 +79,8 @@ var Table = f5.New(func(this *table) {
|
||||
this.FileName = "../res/item@item.json"
|
||||
this.PrimKey = "id"
|
||||
})
|
||||
|
||||
this.Chain = f5.New(func(this *ChainTable) {
|
||||
this.FileName = "../config/erc20.json"
|
||||
})
|
||||
})
|
||||
|
@ -129,6 +129,7 @@ type Item struct {
|
||||
}
|
||||
|
||||
type Erc20 struct {
|
||||
token_name string
|
||||
net_id int32
|
||||
rpc_url string
|
||||
account_address string
|
||||
@ -602,6 +603,14 @@ func (this *Item) HasSubType() bool {
|
||||
return (this._flags1_ & (uint64(1) << 4)) > 0
|
||||
}
|
||||
|
||||
func (this *Erc20) GetTokenName() string {
|
||||
return this.token_name
|
||||
}
|
||||
|
||||
func (this *Erc20) HasTokenName() bool {
|
||||
return (this._flags1_ & (uint64(1) << 1)) > 0
|
||||
}
|
||||
|
||||
func (this *Erc20) GetNetId() int32 {
|
||||
return this.net_id
|
||||
}
|
||||
@ -727,6 +736,7 @@ func (this *Item) LoadFromKv(kv map[string]interface{}) {
|
||||
}
|
||||
|
||||
func (this *Erc20) LoadFromKv(kv map[string]interface{}) {
|
||||
f5.ReadMetaTableField(&this.token_name, "token_name", &this._flags1_, 1, kv)
|
||||
f5.ReadMetaTableField(&this.net_id, "net_id", &this._flags1_, 2, kv)
|
||||
f5.ReadMetaTableField(&this.rpc_url, "rpc_url", &this._flags1_, 3, kv)
|
||||
f5.ReadMetaTableField(&this.account_address, "account_address", &this._flags1_, 4, kv)
|
||||
|
@ -106,6 +106,7 @@ message Item
|
||||
|
||||
message Erc20
|
||||
{
|
||||
optional string token_name = 1;
|
||||
optional int32 net_id = 2;
|
||||
optional string rpc_url = 3;
|
||||
optional string account_address = 4;
|
||||
|
@ -16,5 +16,6 @@ func (nr *NFTRouter) InitNFTRouter(priRouter *gin.RouterGroup) {
|
||||
group.POST("orderquery", middleware.Permission("api/v1/nft/orderquery", api.OrderQuery))
|
||||
group.POST("salequery", middleware.Permission("api/v1/nft/salequery", api.SaleQuery))
|
||||
group.POST("nftquery", middleware.Permission("api/v1/nft/nftquery", api.NFTQuery))
|
||||
group.POST("balancequery", middleware.Permission("api/v1/nft/balancequery", api.BalanceQuery))
|
||||
}
|
||||
}
|
||||
|
196
server/adminserver/service/balance.go
Normal file
196
server/adminserver/service/balance.go
Normal file
@ -0,0 +1,196 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"adminserver/constant"
|
||||
"f5"
|
||||
"fmt"
|
||||
"main/mt"
|
||||
"q5"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type baseinfo struct {
|
||||
recharge int64
|
||||
balance string
|
||||
}
|
||||
|
||||
type addressBalance struct {
|
||||
gcTime int64
|
||||
infoList q5.ConcurrentMap[string, *baseinfo] // <netid$toke_addr, baseinfo>
|
||||
}
|
||||
|
||||
type chainbalance struct {
|
||||
gcTime int64
|
||||
|
||||
infoList q5.ConcurrentMap[string, *baseinfo] // <netid$toke_addr, baseinfo>
|
||||
addressBalanceList q5.ConcurrentMap[string, *addressBalance] // <account, addressBalance>
|
||||
}
|
||||
|
||||
func (this *chainbalance) init() {
|
||||
this.infoList = q5.ConcurrentMap[string, *baseinfo]{}
|
||||
this.addressBalanceList = q5.ConcurrentMap[string, *addressBalance]{}
|
||||
this.GetGlobalBalance("")
|
||||
go this.checkBalanceList()
|
||||
}
|
||||
|
||||
func (this *chainbalance) unInit() {
|
||||
|
||||
}
|
||||
|
||||
func (this *chainbalance) GetAccoutBalance(netidtoken string, acc string) (string, int64) {
|
||||
info, exist := this.addressBalanceList.Load(acc)
|
||||
if !exist {
|
||||
tmpinfo := new(addressBalance)
|
||||
this.addressBalanceList.Store(acc, tmpinfo)
|
||||
info = &tmpinfo
|
||||
}
|
||||
|
||||
if nowseconds := f5.GetApp().GetRealSeconds(); (*info).gcTime+60 < nowseconds {
|
||||
(*info).gcTime = nowseconds
|
||||
this.getChainBalance(acc)
|
||||
}
|
||||
|
||||
v, exist := (*info).infoList.Load(netidtoken)
|
||||
if exist {
|
||||
return (*v).balance, (*v).recharge
|
||||
}
|
||||
|
||||
return "", 0
|
||||
}
|
||||
|
||||
func (this *chainbalance) GetGlobalBalance(netidtoken string) (string, int64) {
|
||||
if nowseconds := f5.GetApp().GetRealSeconds(); this.gcTime+60 < nowseconds {
|
||||
this.gcTime = nowseconds
|
||||
go this.getChainBalance("")
|
||||
}
|
||||
|
||||
v, exist := this.infoList.Load(netidtoken)
|
||||
if exist {
|
||||
return (*v).balance, (*v).recharge
|
||||
}
|
||||
|
||||
return "", 0
|
||||
}
|
||||
|
||||
func (this *chainbalance) getChainBalance(acc string) {
|
||||
tmpmap := q5.ConcurrentMap[string, int32]{}
|
||||
url := mt.Table.Web3ServiceCluster.RandElement().GetUrl() + "/webapp/index.php"
|
||||
mt.Table.Chain.Traverse(func(item *mt.Chain) bool {
|
||||
var info *baseinfo
|
||||
key := fmt.Sprintf("%d$%s", item.GetNetId(), item.GetTokenAddress())
|
||||
if acc == "" {
|
||||
tmp, exist := this.infoList.Load(key)
|
||||
if !exist {
|
||||
info = new(baseinfo)
|
||||
this.infoList.Store(key, info)
|
||||
tmp = &info
|
||||
} else {
|
||||
info = *tmp
|
||||
}
|
||||
} else {
|
||||
accinfo, exist := this.addressBalanceList.Load(acc)
|
||||
if !exist {
|
||||
tmp := new(addressBalance)
|
||||
this.addressBalanceList.Store(acc, tmp)
|
||||
accinfo = &tmp
|
||||
info = new(baseinfo)
|
||||
tmp.infoList.Store(key, info)
|
||||
} else {
|
||||
keyinfo, exist := (*accinfo).infoList.Load(key)
|
||||
if !exist {
|
||||
info = new(baseinfo)
|
||||
(*accinfo).infoList.Store(key, info)
|
||||
} else {
|
||||
info = *keyinfo
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
sql := fmt.Sprintf(`SELECT sum(diamond) FROM t_recharge_order WHERE idx > 0 AND pay_status = 1 AND net_id = %d AND currency_name = '%s'`, item.GetNetId(), strings.ToLower(item.GetTokenAddress()))
|
||||
if acc != "" {
|
||||
sql = fmt.Sprintf(`%s AND account_address = '%s'`, sql, strings.ToLower(acc))
|
||||
}
|
||||
|
||||
f5.GetGoStyleDb().RawQuery(
|
||||
constant.BCNFT_DB,
|
||||
sql,
|
||||
[]string{},
|
||||
func(err error, ds *f5.DataSet) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if ds.Next() {
|
||||
info.recharge = q5.SafeToInt64(ds.GetByIndex(0)) / 100
|
||||
}
|
||||
})
|
||||
|
||||
}
|
||||
rpcurl := item.GetRpcUrl()
|
||||
|
||||
tmpmap.Store(key, 1)
|
||||
doquery := func(account string, tokeaddr string, balance *string) {
|
||||
f5.GetHttpCliMgr().SendGoStyleRequest(
|
||||
url,
|
||||
map[string]string{
|
||||
"c": "Erc20",
|
||||
"a": "getBalance",
|
||||
"rpc_url": rpcurl,
|
||||
"account_address": account,
|
||||
"token_address": tokeaddr,
|
||||
},
|
||||
func(rsp f5.HttpCliResponse) {
|
||||
tmpmap.Delete(key)
|
||||
if rsp.GetErr() != nil {
|
||||
return
|
||||
}
|
||||
rspJson := struct {
|
||||
ErrCode int32 `json:"errcode"`
|
||||
ErrMsg string `json:"errmsg"`
|
||||
Balance string `json:"balance"`
|
||||
}{}
|
||||
if q5.DecodeJson(rsp.GetRawData(), &rspJson) != nil {
|
||||
return
|
||||
}
|
||||
|
||||
*balance = rspJson.Balance
|
||||
})
|
||||
}
|
||||
|
||||
queryAcc := item.GetAccountAddress()
|
||||
if acc != "" {
|
||||
queryAcc = acc
|
||||
}
|
||||
go doquery(queryAcc, item.GetTokenAddress(), &info.balance)
|
||||
return true
|
||||
})
|
||||
|
||||
for tmpmap.GetSize() > 0 {
|
||||
time.Sleep(time.Second)
|
||||
}
|
||||
}
|
||||
|
||||
func (this *chainbalance) checkBalanceList() {
|
||||
fmt.Println("checkBalanceList start")
|
||||
for {
|
||||
if time.Now().UTC().Hour() == 0 && time.Now().UTC().Minute() == 0 {
|
||||
nowseconds := f5.GetApp().GetRealSeconds()
|
||||
deletelist := []string{}
|
||||
this.addressBalanceList.Range(func(key string, value *addressBalance) bool {
|
||||
if value.gcTime+86400 < nowseconds {
|
||||
deletelist = append(deletelist, key)
|
||||
}
|
||||
return true
|
||||
})
|
||||
|
||||
for _, account := range deletelist {
|
||||
this.addressBalanceList.Delete(account)
|
||||
}
|
||||
|
||||
f5.GetSysLog().Info("delete chainbalance address cache count:%d", len(deletelist))
|
||||
}
|
||||
|
||||
time.Sleep((time.Second * 60))
|
||||
}
|
||||
}
|
13
server/adminserver/service/export.go
Normal file
13
server/adminserver/service/export.go
Normal file
@ -0,0 +1,13 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"main/constant"
|
||||
"main/global"
|
||||
)
|
||||
|
||||
var Balance = new(chainbalance)
|
||||
var _serviceMgr = new(serviceMgr)
|
||||
|
||||
func init() {
|
||||
global.RegModule(constant.SERVICE_MGR_MODULE_IDX, _serviceMgr)
|
||||
}
|
12
server/adminserver/service/servicemgr.go
Normal file
12
server/adminserver/service/servicemgr.go
Normal file
@ -0,0 +1,12 @@
|
||||
package service
|
||||
|
||||
type serviceMgr struct {
|
||||
}
|
||||
|
||||
func (this *serviceMgr) Init() {
|
||||
Balance.init()
|
||||
}
|
||||
|
||||
func (this *serviceMgr) UnInit() {
|
||||
Balance.unInit()
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user