Browse Source

add 区块星链

tags/v1.9.6
DengBiao 2 years ago
parent
commit
95e7991d5c
24 changed files with 4103 additions and 0 deletions
  1. +153
    -0
      db/db_block_star_chain.go
  2. +153
    -0
      db/db_block_star_chain_flow.go
  3. +153
    -0
      db/db_block_star_chain_settlement_records.go
  4. +173
    -0
      db/db_user_virtual_amount.go
  5. +153
    -0
      db/db_user_virtual_coin_flow.go
  6. +33
    -0
      db/model/block_star_chain.go
  7. +23
    -0
      db/model/block_star_chain_flow.go
  8. +23
    -0
      db/model/block_star_chain_settlement_records.go
  9. +9
    -0
      db/model/user_virtual_amount.go
  10. +21
    -0
      db/model/user_virtual_coin_flow.go
  11. +47
    -0
      enum/block_star_chain.go
  12. +2
    -0
      go.mod
  13. +3
    -0
      go.sum
  14. +37
    -0
      md/block_star_chain.go
  15. +547
    -0
      rule/block_star_chain_settlement.go
  16. +60
    -0
      svc/svc_block_star_chain_settlement.go
  17. +84
    -0
      svc/svc_redis_mutex_lock.go
  18. +421
    -0
      utils/cache/base.go
  19. +413
    -0
      utils/cache/redis.go
  20. +622
    -0
      utils/cache/redis_cluster.go
  21. +324
    -0
      utils/cache/redis_pool.go
  22. +617
    -0
      utils/cache/redis_pool_cluster.go
  23. +3
    -0
      utils/convert.go
  24. +29
    -0
      utils/time2s.go

+ 153
- 0
db/db_block_star_chain.go View File

@@ -0,0 +1,153 @@
package db

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db/model"
zhios_order_relate_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils"
zhios_order_relate_logx "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/logx"
"errors"
"fmt"
"reflect"
"xorm.io/xorm"
)

// BatchSelectBlockStarChains 批量查询数据 TODO::和下面的方法重复了,建议采用下面的 `BlockStarChainFindByParams` 方法
func BatchSelectBlockStarChains(Db *xorm.Engine, params map[string]interface{}) (*[]model.BlockStarChain, error) {
var BlockStarChainData []model.BlockStarChain
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).
Find(&BlockStarChainData); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &BlockStarChainData, nil
}

// BlockStarChainInsert 插入单条数据
func BlockStarChainInsert(Db *xorm.Engine, BlockStarChain *model.BlockStarChain) (int, error) {
_, err := Db.InsertOne(BlockStarChain)
if err != nil {
return 0, err
}
return BlockStarChain.Id, nil
}

// BatchAddBlockStarChains 批量新增数据
func BatchAddBlockStarChains(Db *xorm.Engine, BlockStarChainData []*model.BlockStarChain) (int64, error) {
affected, err := Db.Insert(BlockStarChainData)
if err != nil {
return 0, err
}
return affected, nil
}

func GetBlockStarChainCount(Db *xorm.Engine) int {
var BlockStarChain model.BlockStarChain
session := Db.Where("")
count, err := session.Count(&BlockStarChain)
if err != nil {
return 0
}
return int(count)
}

// BlockStarChainDelete 删除记录
func BlockStarChainDelete(Db *xorm.Engine, id interface{}) (int64, error) {
if reflect.TypeOf(id).Kind() == reflect.Slice {
return Db.In("id", id).Delete(model.BlockStarChain{})
} else {
return Db.Where("id = ?", id).Delete(model.BlockStarChain{})
}
}

// BlockStarChainUpdate 更新记录
func BlockStarChainUpdate(session *xorm.Session, id interface{}, BlockStarChain *model.BlockStarChain, forceColums ...string) (int64, error) {
var (
affected int64
err error
)
if forceColums != nil {
affected, err = session.Where("id=?", id).Cols(forceColums...).Update(BlockStarChain)
} else {
affected, err = session.Where("id=?", id).Update(BlockStarChain)
}
if err != nil {
return 0, err
}
return affected, nil
}

// BlockStarChainGetOneByParams 通过传入的参数查询数据(单条)
func BlockStarChainGetOneByParams(session *xorm.Session, params map[string]interface{}) (*model.BlockStarChain, error) {
var m model.BlockStarChain
var query = fmt.Sprintf("%s =?", params["key"])
if has, err := session.Where(query, params["value"]).Get(&m); err != nil || has == false {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

// BlockStarChainFindByParams 通过传入的参数查询数据(多条)
func BlockStarChainFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.BlockStarChain, error) {
var m []model.BlockStarChain
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if params["key"] == nil {
//查询全部数据
err := Db.Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

func BlockStarChainFindByParamsByPage(Db *xorm.Engine, params map[string]interface{}, page, pageSize int) (*[]model.BlockStarChain, error) {
var m []model.BlockStarChain
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if page == 0 && pageSize == 0 {
page = 1
pageSize = 10
}

if params["key"] == nil {
//查询全部数据
err := Db.Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

+ 153
- 0
db/db_block_star_chain_flow.go View File

@@ -0,0 +1,153 @@
package db

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db/model"
zhios_order_relate_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils"
zhios_order_relate_logx "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/logx"
"errors"
"fmt"
"reflect"
"xorm.io/xorm"
)

// BatchSelectBlockStarChainFlows 批量查询数据 TODO::和下面的方法重复了,建议采用下面的 `BlockStarChainFlowFindByParams` 方法
func BatchSelectBlockStarChainFlows(Db *xorm.Engine, params map[string]interface{}) (*[]model.BlockStarChainFlow, error) {
var BlockStarChainFlowData []model.BlockStarChainFlow
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).
Find(&BlockStarChainFlowData); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &BlockStarChainFlowData, nil
}

// BlockStarChainFlowInsert 插入单条数据
func BlockStarChainFlowInsert(session *xorm.Session, BlockStarChainFlow *model.BlockStarChainFlow) (int64, error) {
_, err := session.InsertOne(BlockStarChainFlow)
if err != nil {
return 0, err
}
return BlockStarChainFlow.Id, nil
}

// BatchAddBlockStarChainFlows 批量新增数据
func BatchAddBlockStarChainFlows(Db *xorm.Engine, BlockStarChainFlowData []*model.BlockStarChainFlow) (int64, error) {
affected, err := Db.Insert(BlockStarChainFlowData)
if err != nil {
return 0, err
}
return affected, nil
}

func GetBlockStarChainFlowCount(Db *xorm.Engine) int {
var BlockStarChainFlow model.BlockStarChainFlow
session := Db.Where("")
count, err := session.Count(&BlockStarChainFlow)
if err != nil {
return 0
}
return int(count)
}

// BlockStarChainFlowDelete 删除记录
func BlockStarChainFlowDelete(Db *xorm.Engine, id interface{}) (int64, error) {
if reflect.TypeOf(id).Kind() == reflect.Slice {
return Db.In("id", id).Delete(model.BlockStarChainFlow{})
} else {
return Db.Where("id = ?", id).Delete(model.BlockStarChainFlow{})
}
}

// BlockStarChainFlowUpdate 更新记录
func BlockStarChainFlowUpdate(session *xorm.Session, id interface{}, BlockStarChainFlow *model.BlockStarChainFlow, forceColums ...string) (int64, error) {
var (
affected int64
err error
)
if forceColums != nil {
affected, err = session.Where("id=?", id).Cols(forceColums...).Update(BlockStarChainFlow)
} else {
affected, err = session.Where("id=?", id).Update(BlockStarChainFlow)
}
if err != nil {
return 0, err
}
return affected, nil
}

// BlockStarChainFlowGetOneByParams 通过传入的参数查询数据(单条)
func BlockStarChainFlowGetOneByParams(Db *xorm.Engine, params map[string]interface{}) (*model.BlockStarChainFlow, error) {
var m model.BlockStarChainFlow
var query = fmt.Sprintf("%s =?", params["key"])
if has, err := Db.Where(query, params["value"]).Get(&m); err != nil || has == false {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

// BlockStarChainFlowFindByParams 通过传入的参数查询数据(多条)
func BlockStarChainFlowFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.BlockStarChainFlow, error) {
var m []model.BlockStarChainFlow
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if params["key"] == nil {
//查询全部数据
err := Db.Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

func BlockStarChainFlowFindByParamsByPage(Db *xorm.Engine, params map[string]interface{}, page, pageSize int) (*[]model.BlockStarChainFlow, error) {
var m []model.BlockStarChainFlow
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if page == 0 && pageSize == 0 {
page = 1
pageSize = 10
}

if params["key"] == nil {
//查询全部数据
err := Db.Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

+ 153
- 0
db/db_block_star_chain_settlement_records.go View File

@@ -0,0 +1,153 @@
package db

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db/model"
zhios_order_relate_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils"
zhios_order_relate_logx "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/logx"
"errors"
"fmt"
"reflect"
"xorm.io/xorm"
)

// BatchSelectBlockStarChainSettlementRecordss 批量查询数据 TODO::和下面的方法重复了,建议采用下面的 `BlockStarChainSettlementRecordsFindByParams` 方法
func BatchSelectBlockStarChainSettlementRecordss(Db *xorm.Engine, params map[string]interface{}) (*[]model.BlockStarChainSettlementRecords, error) {
var BlockStarChainSettlementRecordsData []model.BlockStarChainSettlementRecords
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).
Find(&BlockStarChainSettlementRecordsData); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &BlockStarChainSettlementRecordsData, nil
}

// BlockStarChainSettlementRecordsInsert 插入单条数据
func BlockStarChainSettlementRecordsInsert(session *xorm.Session, BlockStarChainSettlementRecords *model.BlockStarChainSettlementRecords) (int64, error) {
_, err := session.InsertOne(BlockStarChainSettlementRecords)
if err != nil {
return 0, err
}
return BlockStarChainSettlementRecords.Id, nil
}

// BatchAddBlockStarChainSettlementRecordss 批量新增数据
func BatchAddBlockStarChainSettlementRecordss(Db *xorm.Engine, BlockStarChainSettlementRecordsData []*model.BlockStarChainSettlementRecords) (int64, error) {
affected, err := Db.Insert(BlockStarChainSettlementRecordsData)
if err != nil {
return 0, err
}
return affected, nil
}

func GetBlockStarChainSettlementRecordsCount(Db *xorm.Engine) int {
var BlockStarChainSettlementRecords model.BlockStarChainSettlementRecords
session := Db.Where("")
count, err := session.Count(&BlockStarChainSettlementRecords)
if err != nil {
return 0
}
return int(count)
}

// BlockStarChainSettlementRecordsDelete 删除记录
func BlockStarChainSettlementRecordsDelete(Db *xorm.Engine, id interface{}) (int64, error) {
if reflect.TypeOf(id).Kind() == reflect.Slice {
return Db.In("id", id).Delete(model.BlockStarChainSettlementRecords{})
} else {
return Db.Where("id = ?", id).Delete(model.BlockStarChainSettlementRecords{})
}
}

// BlockStarChainSettlementRecordsUpdate 更新记录
func BlockStarChainSettlementRecordsUpdate(session *xorm.Session, id interface{}, BlockStarChainSettlementRecords *model.BlockStarChainSettlementRecords, forceColums ...string) (int64, error) {
var (
affected int64
err error
)
if forceColums != nil {
affected, err = session.Where("id=?", id).Cols(forceColums...).Update(BlockStarChainSettlementRecords)
} else {
affected, err = session.Where("id=?", id).Update(BlockStarChainSettlementRecords)
}
if err != nil {
return 0, err
}
return affected, nil
}

// BlockStarChainSettlementRecordsGetOneByParams 通过传入的参数查询数据(单条)
func BlockStarChainSettlementRecordsGetOneByParams(Db *xorm.Engine, params map[string]interface{}) (*model.BlockStarChainSettlementRecords, error) {
var m model.BlockStarChainSettlementRecords
var query = fmt.Sprintf("%s =?", params["key"])
if has, err := Db.Where(query, params["value"]).Get(&m); err != nil || has == false {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

// BlockStarChainSettlementRecordsFindByParams 通过传入的参数查询数据(多条)
func BlockStarChainSettlementRecordsFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.BlockStarChainSettlementRecords, error) {
var m []model.BlockStarChainSettlementRecords
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if params["key"] == nil {
//查询全部数据
err := Db.Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

func BlockStarChainSettlementRecordsFindByParamsByPage(Db *xorm.Engine, params map[string]interface{}, page, pageSize int) (*[]model.BlockStarChainSettlementRecords, error) {
var m []model.BlockStarChainSettlementRecords
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if page == 0 && pageSize == 0 {
page = 1
pageSize = 10
}

if params["key"] == nil {
//查询全部数据
err := Db.Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

+ 173
- 0
db/db_user_virtual_amount.go View File

@@ -0,0 +1,173 @@
package db

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db/model"
zhios_order_relate_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils"
zhios_order_relate_logx "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/logx"
"errors"
"fmt"
"reflect"
"xorm.io/xorm"
)

// BatchSelectUserVirtualAmounts 批量查询数据 TODO::和下面的方法重复了,建议采用下面的 `UserVirtualAmountFindByParams` 方法
func BatchSelectUserVirtualAmounts(Db *xorm.Engine, params map[string]interface{}) (*[]model.UserVirtualAmount, error) {
var UserVirtualAmountData []model.UserVirtualAmount
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).
Find(&UserVirtualAmountData); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &UserVirtualAmountData, nil
}

// UserVirtualAmountInsert 插入单条数据
func UserVirtualAmountInsert(Db *xorm.Engine, UserVirtualAmount *model.UserVirtualAmount) (int64, error) {
_, err := Db.InsertOne(UserVirtualAmount)
if err != nil {
return 0, err
}
return UserVirtualAmount.Id, nil
}

// BatchAddUserVirtualAmounts 批量新增数据
func BatchAddUserVirtualAmounts(Db *xorm.Engine, UserVirtualAmountData []*model.UserVirtualAmount) (int64, error) {
affected, err := Db.Insert(UserVirtualAmountData)
if err != nil {
return 0, err
}
return affected, nil
}

func GetUserVirtualAmountCount(Db *xorm.Engine) int {
var UserVirtualAmount model.UserVirtualAmount
session := Db.Where("")
count, err := session.Count(&UserVirtualAmount)
if err != nil {
return 0
}
return int(count)
}

// UserVirtualAmountDelete 删除记录
func UserVirtualAmountDelete(Db *xorm.Engine, id interface{}) (int64, error) {
if reflect.TypeOf(id).Kind() == reflect.Slice {
return Db.In("id", id).Delete(model.UserVirtualAmount{})
} else {
return Db.Where("id = ?", id).Delete(model.UserVirtualAmount{})
}
}

// UserVirtualAmountUpdate 更新记录
func UserVirtualAmountUpdate(session *xorm.Session, id interface{}, UserVirtualAmount *model.UserVirtualAmount, forceColums ...string) (int64, error) {
var (
affected int64
err error
)
if forceColums != nil {
affected, err = session.Where("id=?", id).Cols(forceColums...).Update(UserVirtualAmount)
} else {
affected, err = session.Where("id=?", id).Update(UserVirtualAmount)
}
if err != nil {
return 0, err
}
return affected, nil
}

func GetUserVirtualWalletWithSession(session *xorm.Session, uid, coinId int) (*model.UserVirtualAmount, error) {
var UserVirtualWallet model.UserVirtualAmount
get, err := session.Where("uid = ? AND coin_id = ?", uid, coinId).Get(&UserVirtualWallet)
if err != nil {
return nil, err
}
if get {
return &UserVirtualWallet, nil
} else {
UserVirtualWallet.Amount = "0"
UserVirtualWallet.CoinId = coinId
UserVirtualWallet.Uid = uid
one, err := session.InsertOne(&UserVirtualWallet)
if err != nil || one == 0 {
return nil, err
}
}
return nil, errors.New("获取用户虚拟币钱包失败")
}

// UserVirtualAmountGetOneByParams 通过传入的参数查询数据(单条)
func UserVirtualAmountGetOneByParams(Db *xorm.Engine, params map[string]interface{}) (*model.UserVirtualAmount, error) {
var m model.UserVirtualAmount
var query = fmt.Sprintf("%s =?", params["key"])
if has, err := Db.Where(query, params["value"]).Get(&m); err != nil || has == false {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

// UserVirtualAmountFindByParams 通过传入的参数查询数据(多条)
func UserVirtualAmountFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.UserVirtualAmount, error) {
var m []model.UserVirtualAmount
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if params["key"] == nil {
//查询全部数据
err := Db.Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

func UserVirtualAmountFindByParamsByPage(Db *xorm.Engine, params map[string]interface{}, page, pageSize int) (*[]model.UserVirtualAmount, error) {
var m []model.UserVirtualAmount
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if page == 0 && pageSize == 0 {
page = 1
pageSize = 10
}

if params["key"] == nil {
//查询全部数据
err := Db.Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

+ 153
- 0
db/db_user_virtual_coin_flow.go View File

@@ -0,0 +1,153 @@
package db

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db/model"
zhios_order_relate_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils"
zhios_order_relate_logx "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/logx"
"errors"
"fmt"
"reflect"
"xorm.io/xorm"
)

// BatchSelectUserVirtualCoinFlows 批量查询数据 TODO::和下面的方法重复了,建议采用下面的 `UserVirtualCoinFlowFindByParams` 方法
func BatchSelectUserVirtualCoinFlows(Db *xorm.Engine, params map[string]interface{}) (*[]model.UserVirtualCoinFlow, error) {
var UserVirtualCoinFlowData []model.UserVirtualCoinFlow
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).
Find(&UserVirtualCoinFlowData); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &UserVirtualCoinFlowData, nil
}

// UserVirtualCoinFlowInsert 插入单条数据
func UserVirtualCoinFlowInsert(session *xorm.Session, UserVirtualCoinFlow *model.UserVirtualCoinFlow) (int64, error) {
_, err := session.InsertOne(UserVirtualCoinFlow)
if err != nil {
return 0, err
}
return UserVirtualCoinFlow.Id, nil
}

// BatchAddUserVirtualCoinFlows 批量新增数据
func BatchAddUserVirtualCoinFlows(Db *xorm.Engine, UserVirtualCoinFlowData []*model.UserVirtualCoinFlow) (int64, error) {
affected, err := Db.Insert(UserVirtualCoinFlowData)
if err != nil {
return 0, err
}
return affected, nil
}

func GetUserVirtualCoinFlowCount(Db *xorm.Engine) int {
var UserVirtualCoinFlow model.UserVirtualCoinFlow
session := Db.Where("")
count, err := session.Count(&UserVirtualCoinFlow)
if err != nil {
return 0
}
return int(count)
}

// UserVirtualCoinFlowDelete 删除记录
func UserVirtualCoinFlowDelete(Db *xorm.Engine, id interface{}) (int64, error) {
if reflect.TypeOf(id).Kind() == reflect.Slice {
return Db.In("id", id).Delete(model.UserVirtualCoinFlow{})
} else {
return Db.Where("id = ?", id).Delete(model.UserVirtualCoinFlow{})
}
}

// UserVirtualCoinFlowUpdate 更新记录
func UserVirtualCoinFlowUpdate(session *xorm.Session, id interface{}, UserVirtualCoinFlow *model.UserVirtualCoinFlow, forceColums ...string) (int64, error) {
var (
affected int64
err error
)
if forceColums != nil {
affected, err = session.Where("id=?", id).Cols(forceColums...).Update(UserVirtualCoinFlow)
} else {
affected, err = session.Where("id=?", id).Update(UserVirtualCoinFlow)
}
if err != nil {
return 0, err
}
return affected, nil
}

// UserVirtualCoinFlowGetOneByParams 通过传入的参数查询数据(单条)
func UserVirtualCoinFlowGetOneByParams(Db *xorm.Engine, params map[string]interface{}) (*model.UserVirtualCoinFlow, error) {
var m model.UserVirtualCoinFlow
var query = fmt.Sprintf("%s =?", params["key"])
if has, err := Db.Where(query, params["value"]).Get(&m); err != nil || has == false {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

// UserVirtualCoinFlowFindByParams 通过传入的参数查询数据(多条)
func UserVirtualCoinFlowFindByParams(Db *xorm.Engine, params map[string]interface{}) (*[]model.UserVirtualCoinFlow, error) {
var m []model.UserVirtualCoinFlow
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if params["key"] == nil {
//查询全部数据
err := Db.Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

func UserVirtualCoinFlowFindByParamsByPage(Db *xorm.Engine, params map[string]interface{}, page, pageSize int) (*[]model.UserVirtualCoinFlow, error) {
var m []model.UserVirtualCoinFlow
if params["value"] == nil {
return nil, errors.New("参数有误")
}
if page == 0 && pageSize == 0 {
page = 1
pageSize = 10
}

if params["key"] == nil {
//查询全部数据
err := Db.Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
} else {
if reflect.TypeOf(params["value"]).Kind() == reflect.Slice {
//指定In查询
if err := Db.In(zhios_order_relate_utils.AnyToString(params["key"]), params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m); err != nil {
return nil, zhios_order_relate_logx.Warn(err)
}
return &m, nil
} else {
var query = fmt.Sprintf("%s =?", params["key"])
err := Db.Where(query, params["value"]).Limit(pageSize, (page-1)*pageSize).Find(&m)
if err != nil {
return nil, zhios_order_relate_logx.Error(err)
}
return &m, nil
}

}
}

+ 33
- 0
db/model/block_star_chain.go View File

@@ -0,0 +1,33 @@
package model

import (
"time"
)

type BlockStarChain struct {
Id int `json:"id" xorm:"not null pk autoincr comment('主键id') INT(11)"`
IsUse int `json:"is_use" xorm:"not null default 0 comment('是否开启(否:0;是:1)') TINYINT(1)"`
Coin1 int `json:"coin_1" xorm:"not null default 0 comment('coinId_1(类似于区块币)') INT(11)"`
Coin2 int `json:"coin_2" xorm:"not null default 0 comment('coinId_2(类似于静态贡献值)') INT(11)"`
Coin3 int `json:"coin_3" xorm:"not null default 0 comment('coinId_3(类似于动态贡献值)') INT(11)"`
InitialEverydayPublishCoin string `json:"initial_everyday_publish_coin" xorm:"not null default 0.0000000000 comment('初始每日区块币发行数量') DECIMAL(28,10)"`
NowEverydayPublishCoin string `json:"now_everyday_publish_coin" xorm:"not null default 0.0000000000 comment('当前每日区块币发行数量') DECIMAL(28,10)"`
TodayPublishCoin string `json:"today_publish_coin" xorm:"not null default 0.0000000000 comment('今日区块币发行数量(若为0,则按当前每日区块币发行数量)') DECIMAL(28,10)"`
EveryThirtyDaysReduceRate string `json:"every_thirty_days_reduce_rate" xorm:"not null default 5.00 comment('每三十日递减发行百分比') DECIMAL(5,2)"`
TotalNowCoin string `json:"total_now_coin" xorm:"not null default 0.0000000000 comment('当前区块币总量') DECIMAL(28,10)"`
TotalPublishCoin string `json:"total_publish_coin" xorm:"not null default 0.0000000000 comment('累计区块币发行总量') DECIMAL(28,10)"`
TotalDestroyCoin string `json:"total_destroy_coin" xorm:"not null default 0.0000000000 comment('累计区块币销毁总量') DECIMAL(28,10)"`
TotalRemainderCoin string `json:"total_remainder_coin" xorm:"not null default 0.0000000000 comment('累计区块币剩余总量') DECIMAL(28,10)"`
InitialCoinTotal string `json:"initial_coin_total" xorm:"not null default 0.0000000000 comment('初始区块币总量') DECIMAL(28,10)"`
PlatformGuidePriceForCoin string `json:"platform_guide_price_for_coin" xorm:"not null default 0.0000000000 comment('平台区块币指导价') DECIMAL(22,10)"`
StartAt string `json:"start_at" xorm:"not null default '' comment('起始时间(0000-00)') CHAR(50)"`
PlatformBusinessDiscountRate string `json:"platform_business_discount_rate" xorm:"not null default 0.00 comment('平台商家让利百分比') DECIMAL(5,2)"`
ConsumeReturnContributionRate string `json:"consume_return_contribution_rate" xorm:"not null default 100.00 comment('消费返贡献值比例') DECIMAL(5,2)"`
PublishCoinDynamicRate string `json:"publish_coin_dynamic_rate" xorm:"not null default 45.00 comment('区块币发行动态占比') DECIMAL(5,2)"`
PublishCoinStaticRate string `json:"publish_coin_static_rate" xorm:"not null default 45.00 comment('区块币发行静态占比') DECIMAL(5,2)"`
PublishCoinOperationCenterRate string `json:"publish_coin_operation_center_rate" xorm:"not null default 3.00 comment('区块币发行运营中心占比') DECIMAL(5,2)"`
PublishCoinOperationOtherRate string `json:"publish_coin_other_rate" xorm:"not null default 7.00 comment('区块币发行其他占比') DECIMAL(5,2)"`
RewardSettings string `json:"reward_settings" xorm:"comment('奖励设置') TEXT"`
CreateAt time.Time `json:"create_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') TIMESTAMP"`
UpdateAt time.Time `json:"update_at" xorm:"default 'CURRENT_TIMESTAMP' comment('更新时间') TIMESTAMP"`
}

+ 23
- 0
db/model/block_star_chain_flow.go View File

@@ -0,0 +1,23 @@
package model

import (
"time"
)

type BlockStarChainFlow struct {
Id int64 `json:"id" xorm:"pk autoincr BIGINT(20)"`
CoinId int `json:"coin_id" xorm:"not null comment('虚拟币id') INT(11)"`
Direction int `json:"direction" xorm:"not null default 1 comment('方向:1收入 2支出') TINYINT(255)"`
Kind int `json:"kind" xorm:"not null default 1 comment('种类(1:系统定时发放 2:系统销毁 3:静态未分配完销毁 4:动态未分配完销毁 4:运营中心未分配完销毁 5:运营中心未分配完销毁 6:打赏销毁 7:打赏未分配完销毁 7:自营拼团抽奖销毁 8:红包转余额销毁 9:转增手续费销毁)') TINYINT(1)"`
Title string `json:"title" xorm:"not null default '' comment('标题') VARCHAR(255)"`
Amount string `json:"amount" xorm:"not null comment('变更数量') DECIMAL(28,10)"`
BeforeTotalNowCoin string `json:"before_total_now_coin" xorm:"not null default 0.0000000000 comment('变更前-区块币总量') DECIMAL(28,10)"`
AfterTotalNowCoin string `json:"after_total_now_coin" xorm:"not null default 0.0000000000 comment('变更后-区块币总量') DECIMAL(28,10)"`
BeforeTotalRemainderCoin string `json:"before_total_remainder_coin" xorm:"not null default 0.0000000000 comment('变更前-累计区块币剩余总量') DECIMAL(28,10)"`
AfterTotalRemainderCoin string `json:"after_total_remainder_coin" xorm:"not null default 0.0000000000 comment('变更后-累计区块币剩余总量') DECIMAL(28,10)"`
BeforeTotalPublishCoin string `json:"before_total_publish_coin" xorm:"default 0.0000000000 comment('变更前-累计区块币发行总量') DECIMAL(28,10)"`
AfterTotalPublishCoin string `json:"after_total_publish_coin" xorm:"default 0.0000000000 comment('变更后-累计区块币发行总量') DECIMAL(28,10)"`
BeforeTotalDestroyCoin string `json:"before_total_destroy_coin" xorm:"default 0.0000000000 comment('变更前-累计区块币销毁总量') DECIMAL(28,10)"`
AfterTotalDestroyCoin string `json:"after_total_destroy_coin" xorm:"default 0.0000000000 comment('变更后-累计区块币销毁总量') DECIMAL(28,10)"`
CreateTime time.Time `json:"create_time" xorm:"default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"`
}

+ 23
- 0
db/model/block_star_chain_settlement_records.go View File

@@ -0,0 +1,23 @@
package model

import (
"time"
)

type BlockStarChainSettlementRecords struct {
Id int64 `json:"id" xorm:"pk autoincr BIGINT(20)"`
CoinId int `json:"coin_id" xorm:"not null comment('虚拟币id') INT(11)"`
TodayPublishCoin string `json:"today_publish_coin" xorm:"not null default 0.0000000000 comment('今日区块币发行总数量') DECIMAL(28,10)"`
TodayDestroyCoinForSystem string `json:"today_destroy_coin_for_system" xorm:"not null default 0.0000000000 comment('今日销毁区块币数量-系统') DECIMAL(28,10)"`
TodayPublishCoinForStatic string `json:"today_publish_coin_for_static" xorm:"not null default 0.0000000000 comment('今日区块币发行数量-静态区') DECIMAL(28,10)"`
TodayDestroyCoinForStatic string `json:"today_destroy_coin_for_static" xorm:"not null default 0.0000000000 comment('今日销毁区块币数量-静态区') DECIMAL(28,10)"`
TodayPublishCoinForDynamic string `json:"today_publish_coin_for_dynamic" xorm:"not null default 0.0000000000 comment('今日区块币发行数量-动态区') DECIMAL(28,10)"`
TodayDestroyCoinForDynamic string `json:"today_destroy_coin_for_dynamic" xorm:"not null default 0.0000000000 comment('今日销毁区块币数量-动态区') DECIMAL(28,10)"`
TodayPublishCoinForOperationCenter string `json:"today_publish_coin_for_operation_center" xorm:"not null default 0.0000000000 comment('今日区块币发行数量-运营中心') DECIMAL(28,10)"`
TodayDestroyCoinForOperationCenter string `json:"today_destroy_coin_for_operation_center" xorm:"not null default 0.0000000000 comment('今日销毁区块币数量-运营中心') DECIMAL(28,10)"`
TodayPublishCoinForOther string `json:"today_publish_coin_for_other" xorm:"not null default 0.0000000000 comment('今日区块币发行数量-其他') DECIMAL(28,10)"`
TodayDestroyCoinForOther string `json:"today_destroy_coin_for_other" xorm:"not null default 0.0000000000 comment('今日销毁区块币数量-其他') DECIMAL(28,10)"`
Date string `json:"date" xorm:"not null default '' comment('日期(0000-00)') VARCHAR(50)"`
CreateAt time.Time `json:"create_at" xorm:"not null default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"`
UpdateAt time.Time `json:"update_at" xorm:"not null default 'CURRENT_TIMESTAMP' DATETIME"`
}

+ 9
- 0
db/model/user_virtual_amount.go View File

@@ -0,0 +1,9 @@
package model

type UserVirtualAmount struct {
Id int64 `json:"id" xorm:"pk autoincr BIGINT(20)"`
Uid int `json:"uid" xorm:"index INT(11)"`
CoinId int `json:"coin_id" xorm:"INT(11)"`
Amount string `json:"amount" xorm:"DECIMAL(16,6)"`
FreezeAmount string `json:"freeze_amount" xorm:"DECIMAL(16,6)"`
}

+ 21
- 0
db/model/user_virtual_coin_flow.go View File

@@ -0,0 +1,21 @@
package model

import (
"time"
)

type UserVirtualCoinFlow struct {
Id int64 `json:"id" xorm:"pk autoincr BIGINT(20)"`
Uid int `json:"uid" xorm:"not null comment('用户id') index INT(11)"`
CoinId int `json:"coin_id" xorm:"not null comment('虚拟币id') INT(11)"`
Direction int `json:"direction" xorm:"not null comment('方向:1收入 2支出') TINYINT(255)"`
Title string `json:"title" xorm:"comment('标题') VARCHAR(255)"`
OrdId string `json:"ord_id" xorm:"comment('相关的订单id') VARCHAR(255)"`
Amout string `json:"amout" xorm:"not null comment('变更数量') DECIMAL(16,6)"`
BeforeAmout string `json:"before_amout" xorm:"not null comment('变更前数量') DECIMAL(16,6)"`
AfterAmout string `json:"after_amout" xorm:"not null comment('变更后数量') DECIMAL(16,6)"`
SysFee string `json:"sys_fee" xorm:"not null default 0.000000 comment('手续费') DECIMAL(16,6)"`
CreateTime time.Time `json:"create_time" xorm:"created default 'CURRENT_TIMESTAMP' comment('创建时间') DATETIME"`
TransferType int `json:"transfer_type" xorm:"comment('转账类型:1全球分红,2管理员修改,3消费,4退回,5虚拟币兑换') TINYINT(100)"`
CoinIdTo int `json:"coin_id_to" xorm:"not null default 0 comment('兑换时目标币种id') INT(11)"`
}

+ 47
- 0
enum/block_star_chain.go View File

@@ -0,0 +1,47 @@
package enum

// 退款状态
type BlockStarChainFlowKind int

const (
SystemTimingIssue BlockStarChainFlowKind = iota
SystemDestroy
StaticUnallocatedAndDestroy
DynamicallyUnallocatedAndDestroy
OperationCenterUnallocatedAndDestroy
OtherUnallocatedAndDestroy
RewardDestroy
RewardUnallocatedAndDestroy
GroupLotteryAndDestroy
RedEnvelopeTransferBalanceAndDestroy
TransferFeeAndDestroy
)

func (kind BlockStarChainFlowKind) String() string {
switch kind {
case SystemTimingIssue:
return "系统定时发放"
case SystemDestroy:
return "系统销毁"
case StaticUnallocatedAndDestroy:
return "静态未分配完销毁"
case DynamicallyUnallocatedAndDestroy:
return "动态未分配完销毁"
case OperationCenterUnallocatedAndDestroy:
return "运营中心未分配完销毁"
case OtherUnallocatedAndDestroy:
return "其他未分配完销毁"
case RewardDestroy:
return "打赏销毁"
case RewardUnallocatedAndDestroy:
return "打赏未分配完销毁"
case GroupLotteryAndDestroy:
return "自营拼团抽奖销毁"
case RedEnvelopeTransferBalanceAndDestroy:
return "红包转余额销毁"
case TransferFeeAndDestroy:
return "转增手续费销毁"
default:
return "未知状态"
}
}

+ 2
- 0
go.mod View File

@@ -3,6 +3,8 @@ module code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git
go 1.15

require (
github.com/go-redis/redis v6.15.9+incompatible
github.com/gomodule/redigo v1.8.9 // indirect
github.com/jinzhu/copier v0.3.5
github.com/syyongx/php2go v0.9.6
go.uber.org/zap v1.13.0


+ 3
- 0
go.sum View File

@@ -71,6 +71,7 @@ github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgO
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
@@ -96,6 +97,8 @@ github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8l
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/gomodule/redigo v1.8.9 h1:Sl3u+2BI/kk+VEatbj0scLdrFhjPmbxOc1myhDP41ws=
github.com/gomodule/redigo v1.8.9/go.mod h1:7ArFNvsTjH8GMMzB4uy1snslv2BwmginuMs06a1uzZE=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=


+ 37
- 0
md/block_star_chain.go View File

@@ -0,0 +1,37 @@
package md

const (
FlowDirectionIncome = 1 //流水 - 收入
FlowDirectionExpenditure = 2 //流水 - 支出
)

const (
RedisDataBase = 2 //TODO::区块星链的缓存统一存入redis 2 号库
UserVirtualAmountRedisKey = "%s:user_virtual_amount:%d:user:%d"
)

const (
StaticAreaDistributionTitleForUserVirtualCoinFlow = "区块星链-静态区发放"
DynamicAreaDistributionTitleForUserVirtualCoinFlow = "区块星链-动态区发放"
StaticIssueAndDestroyStaticContributionTitleForUserVirtualCoinFlow = "区块星链-静态发放(销毁静态贡献值)"
DynamicIssueAndDestroyStaticContributionTitleForUserVirtualCoinFlow = "区块星链-动态发放(销毁静态贡献值)"
)
const (
StaticAreaDistributionTransferTypeForUserVirtualCoinFlow = 100
DynamicAreaDistributionTransferTypeForUserVirtualCoinFlow = 101
StaticIssueAndDestroyStaticContributionTransferTypeForUserVirtualCoinFlow = 102
DynamicIssueAndDestroyStaticContributionTransferTypeForUserVirtualCoinFlow = 103
)

const DealUserCoinRequestIdPrefix = "%s:block_star_chain_deal_user_coin:%d:uid:%d"

type DealUserCoinReq struct {
Kind string `json:"kind"`
Mid string `json:"mid"`
Title string `json:"title"`
TransferType int `json:"transfer_type"`
OrdId string `json:"ord_id"`
CoinId int `json:"coin_id"`
Uid int `json:"uid"`
Amount float64 `json:"amount"`
}

+ 547
- 0
rule/block_star_chain_settlement.go View File

@@ -0,0 +1,547 @@
package rule

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db/model"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/enum"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/md"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/svc"
zhios_order_relate_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/cache"
zhios_order_relate_logx "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/logx"
"errors"
"fmt"
"github.com/shopspring/decimal"
"strconv"
"time"
"xorm.io/xorm"
)

func Init(redisAddr string) (err error) {
if redisAddr != "" {
cache.NewRedis(redisAddr)
}
_, err = cache.SelectDb(md.RedisDataBase)
return
}

// DailySettlementBlockStarChain 每日结算“区块星链”
func DailySettlementBlockStarChain(engine *xorm.Engine, mid string) (err error) {
session := engine.NewSession()
defer func() {
session.Close()
if err := recover(); err != nil {
_ = zhios_order_relate_logx.Error(err)
}
}()
session.Begin()
now := time.Now()

//1、查找 `block_star_chain` 基础设置
blockStarChain, err := db.BlockStarChainGetOneByParams(session, map[string]interface{}{
"key": "is_use",
"value": 1,
})
if err != nil {
_ = session.Rollback()
return
}
//initialCoinTotal := zhios_order_relate_utils.StrToFloat64(blockStarChain.InitialCoinTotal) //初始区块币总量
todayPublishCoin := zhios_order_relate_utils.StrToFloat64(blockStarChain.TodayPublishCoin) //今日区块币发行数量(若为0,则按当前每日区块币发行数量)
nowEverydayPublishCoin := zhios_order_relate_utils.StrToFloat64(blockStarChain.NowEverydayPublishCoin) //当前每日区块币发行数量
var publishCoin = todayPublishCoin

//2、判断今日是否有系统销毁
var destroyCoinForSystem string
if todayPublishCoin != 0 && todayPublishCoin != nowEverydayPublishCoin {
destroyCoinForSystem = decimal.NewFromFloat(nowEverydayPublishCoin).Sub(decimal.NewFromFloat(todayPublishCoin)).String()
err := DealDestroyCoin(session, int(enum.SystemDestroy), zhios_order_relate_utils.StrToFloat64(destroyCoinForSystem), enum.SystemDestroy.String(), blockStarChain)
if err != nil {
_ = session.Rollback()
return
}
publishCoin = nowEverydayPublishCoin
}

//3、进行系统区块币发放
err = dealIssueCoin(session, int(enum.SystemDestroy), publishCoin, enum.SystemTimingIssue.String(), blockStarChain)
if err != nil {
_ = session.Rollback()
return
}

//4、进行静态区-区块币统计分配
var staticAreaCoinNums float64 //静态区分配区块币总数
publishCoinStaticRate, _ := decimal.NewFromString(blockStarChain.PublishCoinStaticRate) //区块币发行静态占比
publishCoinStaticRate = publishCoinStaticRate.Div(decimal.NewFromFloat(100))
staticAreaCoinNums = zhios_order_relate_utils.StrToFloat64(decimal.NewFromFloat(publishCoin).Mul(publishCoinStaticRate).String())
err, destroyCoinForStatic := statisticsAndDistributeCoinForStatic(session, mid, staticAreaCoinNums, *blockStarChain)
if err != nil {
_ = session.Rollback()
return
}

//5、进行动态区-区块币统计分配
var dynamicAreaCoinNums float64 //动态区分配区块币总数
publishCoinDynamicRate, _ := decimal.NewFromString(blockStarChain.PublishCoinDynamicRate) //区块币发行动态占比
publishCoinDynamicRate = publishCoinDynamicRate.Div(decimal.NewFromFloat(100))
dynamicAreaCoinNums = zhios_order_relate_utils.StrToFloat64(decimal.NewFromFloat(publishCoin).Mul(publishCoinDynamicRate).String())
err, destroyCoinForDynamic := statisticsAndDistributeCoinForDynamic(session, mid, dynamicAreaCoinNums, *blockStarChain)
if err != nil {
_ = session.Rollback()
return
}

//6、进行运营中心-区块币统计 TODO::未完成分配
var operationCenterCoinNums float64 //动态区分配区块币总数
publishCoinOperationCenterRate, _ := decimal.NewFromString(blockStarChain.PublishCoinOperationCenterRate) //区块币发行动态占比
publishCoinOperationCenterRate = publishCoinOperationCenterRate.Div(decimal.NewFromFloat(100))
operationCenterCoinNums = zhios_order_relate_utils.StrToFloat64(decimal.NewFromFloat(publishCoin).Mul(publishCoinOperationCenterRate).String())

//7、进行其他-区块币统计 TODO::未完成分配
var otherCoinNums float64 //动态区分配区块币总数
publishCoinOperationOtherRate, _ := decimal.NewFromString(blockStarChain.PublishCoinOperationOtherRate) //区块币发行动态占比
publishCoinOperationOtherRate = publishCoinOperationOtherRate.Div(decimal.NewFromFloat(100))
otherCoinNums = zhios_order_relate_utils.StrToFloat64(decimal.NewFromFloat(publishCoin).Mul(publishCoinOperationOtherRate).String())

//8、插入 block_star_chain_settlement_records 记录
var blockStarChainSettlementRecords = model.BlockStarChainSettlementRecords{
CoinId: blockStarChain.Coin1,
TodayPublishCoin: zhios_order_relate_utils.Float64ToStr(publishCoin),
TodayDestroyCoinForSystem: destroyCoinForSystem,
TodayPublishCoinForStatic: zhios_order_relate_utils.Float64ToStr(staticAreaCoinNums),
TodayDestroyCoinForStatic: zhios_order_relate_utils.Float64ToStr(destroyCoinForStatic),
TodayPublishCoinForDynamic: zhios_order_relate_utils.Float64ToStr(dynamicAreaCoinNums),
TodayDestroyCoinForDynamic: zhios_order_relate_utils.Float64ToStr(destroyCoinForDynamic),
TodayPublishCoinForOperationCenter: zhios_order_relate_utils.Float64ToStr(operationCenterCoinNums),
TodayDestroyCoinForOperationCenter: "",
TodayPublishCoinForOther: zhios_order_relate_utils.Float64ToStr(otherCoinNums),
TodayDestroyCoinForOther: "",
Date: now.Format("2006-01"),
CreateAt: now,
UpdateAt: now,
}
_, err = db.BlockStarChainSettlementRecordsInsert(session, &blockStarChainSettlementRecords)
if err != nil {
_ = session.Rollback()
return
}

//6、计算当前每日区块币应发行数量
err = calcNowEverydayPublishCoin(session, *blockStarChain)
if err != nil {
_ = session.Rollback()
return
}
return nil
}

/*
统计分配区块币-静态区
TODO:: 公式【 个人贡献值/全网贡献值x2100枚=每天获取的惠积分 】
*/
func statisticsAndDistributeCoinForStatic(session *xorm.Session, mid string, publishCoin float64, chain model.BlockStarChain) (err error, unassignedTotalCoinValue float64) {
publishCoinValue := decimal.NewFromFloat(publishCoin) //静态区发行区块币数量
platformGuidePriceForCoinValue := decimal.NewFromFloat(zhios_order_relate_utils.StrToFloat64(chain.PlatformGuidePriceForCoin)) //今日平台区块币指导价
var unassignedTotalCoin = decimal.NewFromFloat(0) //未分配完的区块币
var userVirtualAmount model.UserVirtualAmount
var userVirtualAmounts []model.UserVirtualAmount
//1、统计出静态区总贡献值
sumStatic, err := session.Table("user_virtual_amount").Where("coin_id =?", chain.Coin2).Sum(&userVirtualAmount, "amount")
if err != nil {
return
}
sumStaticValue := decimal.NewFromFloat(sumStatic)

//2、查询出所有拥有静态贡献值的用户
err = session.Table("user_virtual_amount").Where("coin_id =?", chain.Coin2).And("amount > 0").Find(&userVirtualAmounts)
if err != nil {
return
}

for _, item := range userVirtualAmounts {
amount := decimal.NewFromFloat(zhios_order_relate_utils.StrToFloat64(item.Amount)) //用户贡献值余额
getCoin := amount.Div(sumStaticValue).Mul(publishCoinValue) //得到的区块币
needDestroyContribution := getCoin.Mul(platformGuidePriceForCoinValue) //需销毁贡献值
//3.1判断静态贡献值是否足够
if needDestroyContribution.GreaterThan(amount) {
//TODO::公式【得到的区块币 - ((需销毁贡献值 - 用户贡献值余额) / 今日平台区块币指导价)】
tempCoin := (needDestroyContribution.Sub(amount)).Div(platformGuidePriceForCoinValue)
getCoin = getCoin.Sub(tempCoin)
unassignedTotalCoin.Add(tempCoin)
needDestroyContribution = amount
}

//3.2给相应用户加上分配到的虚拟币
err := DealUserCoin(session, md.DealUserCoinReq{
Kind: "add",
Mid: mid,
Title: md.StaticAreaDistributionTitleForUserVirtualCoinFlow,
TransferType: md.StaticAreaDistributionTransferTypeForUserVirtualCoinFlow,
OrdId: "",
CoinId: chain.Coin1,
Uid: item.Uid,
Amount: zhios_order_relate_utils.StrToFloat64(getCoin.String()),
})
if err != nil {
return
}

//3.3给相应用户扣除 "静态发放(销毁静态贡献值)"
err = DealUserCoin(session, md.DealUserCoinReq{
Kind: "sub",
Mid: mid,
Title: md.StaticIssueAndDestroyStaticContributionTitleForUserVirtualCoinFlow,
TransferType: md.StaticIssueAndDestroyStaticContributionTransferTypeForUserVirtualCoinFlow,
OrdId: "",
CoinId: chain.Coin2,
Uid: item.Uid,
Amount: zhios_order_relate_utils.StrToFloat64(getCoin.String()),
})
if err != nil {
return
}
}

//4、处理未分配完的区块币-静态区
unassignedTotalCoinValue = zhios_order_relate_utils.StrToFloat64(unassignedTotalCoin.String())
if unassignedTotalCoinValue > 0 {
err := DealDestroyCoin(session, int(enum.StaticUnallocatedAndDestroy), unassignedTotalCoinValue, enum.StaticUnallocatedAndDestroy.String(), &chain)
if err != nil {
return
}
}
return
}

/*
统计分配区块币-动态区
*/
func statisticsAndDistributeCoinForDynamic(session *xorm.Session, mid string, publishCoin float64, chain model.BlockStarChain) (err error, unassignedTotalCoinValue float64) {
publishCoinValue := decimal.NewFromFloat(publishCoin) //动态区发行区块币数量
platformGuidePriceForCoinValue := decimal.NewFromFloat(zhios_order_relate_utils.StrToFloat64(chain.PlatformGuidePriceForCoin)) //今日平台区块币指导价
var unassignedTotalCoin = decimal.NewFromFloat(0) //未分配完的区块币
var userVirtualAmount model.UserVirtualAmount
var userVirtualAmounts []model.UserVirtualAmount
//1、统计出动态区总贡献值
sumStatic, err := session.Table("user_virtual_amount").Where("coin_id =?", chain.Coin3).Sum(&userVirtualAmount, "amount")
if err != nil {
return
}
sumStaticValue := decimal.NewFromFloat(sumStatic)

//2、查询出所有拥有动态贡献值的用户
err = session.Table("user_virtual_amount").Where("coin_id =?", chain.Coin3).And("amount > 0").Find(&userVirtualAmounts)
if err != nil {
return
}

//3、循环处理每个用户的数据(增加虚拟币,扣除静态贡献值)
for _, item := range userVirtualAmounts {
amount := decimal.NewFromFloat(zhios_order_relate_utils.StrToFloat64(item.Amount)) //用户贡献值余额
getCoin := amount.Div(sumStaticValue).Mul(publishCoinValue) //得到的区块币
needDestroyContribution := getCoin.Mul(platformGuidePriceForCoinValue) //需销毁贡献值
//3.1判断静态贡献值是否足够
if needDestroyContribution.GreaterThan(amount) {
//TODO::公式【得到的区块币 - ((需销毁贡献值 - 用户贡献值余额) / 今日平台区块币指导价)】
tempCoin := (needDestroyContribution.Sub(amount)).Div(platformGuidePriceForCoinValue)
getCoin = getCoin.Sub(tempCoin)
unassignedTotalCoin.Add(tempCoin)
needDestroyContribution = amount
}

//3.2给相应用户加上分配到的虚拟币
err := DealUserCoin(session, md.DealUserCoinReq{
Kind: "add",
Mid: mid,
Title: md.DynamicAreaDistributionTitleForUserVirtualCoinFlow,
TransferType: md.DynamicAreaDistributionTransferTypeForUserVirtualCoinFlow,
OrdId: "",
CoinId: chain.Coin1,
Uid: item.Uid,
Amount: zhios_order_relate_utils.StrToFloat64(getCoin.String()),
})
if err != nil {
return
}

//3.3给相应用户扣除 "动态发放(销毁静态贡献值)"
err = DealUserCoin(session, md.DealUserCoinReq{
Kind: "sub",
Mid: mid,
Title: md.DynamicIssueAndDestroyStaticContributionTitleForUserVirtualCoinFlow,
TransferType: md.DynamicIssueAndDestroyStaticContributionTransferTypeForUserVirtualCoinFlow,
OrdId: "",
CoinId: chain.Coin2,
Uid: item.Uid,
Amount: zhios_order_relate_utils.StrToFloat64(getCoin.String()),
})
if err != nil {
return
}
}

//4、处理未分配完的区块币-动态区
unassignedTotalCoinValue = zhios_order_relate_utils.StrToFloat64(unassignedTotalCoin.String())
if unassignedTotalCoinValue > 0 {
err := DealDestroyCoin(session, int(enum.DynamicallyUnallocatedAndDestroy), unassignedTotalCoinValue, enum.DynamicallyUnallocatedAndDestroy.String(), &chain)
if err != nil {
return
}
}
return
}

//计算当前每日区块币应发行数量
func calcNowEverydayPublishCoin(session *xorm.Session, chain model.BlockStarChain) error {
now := time.Now()
startAt := zhios_order_relate_utils.String2Time(chain.StartAt) //起始时间
diffDays := zhios_order_relate_utils.GetDiffDays(now, startAt) //相差天数
remainder := diffDays % 30
if remainder == 0 {
everyThirtyDaysReduceRate := zhios_order_relate_utils.StrToFloat64(chain.EveryThirtyDaysReduceRate) / 100 //每三十日递减发行百分比
nowEverydayPublishCoin := zhios_order_relate_utils.StrToFloat64(chain.NowEverydayPublishCoin) //当前每日区块币发行数量
chain.NowEverydayPublishCoin = zhios_order_relate_utils.Float64ToStrPrec10(nowEverydayPublishCoin * (1 - everyThirtyDaysReduceRate))
updateAffected, err := db.BlockStarChainUpdate(session, chain.Id, &chain, "now_everyday_publish_coin")
if err != nil {
return err
}
if updateAffected == 0 {
err = errors.New("更新 block_star_chain 的 now_everyday_publish_coin 记录失败")
return err
}
}
return nil
}

//处理虚拟币 - 发放
func dealIssueCoin(session *xorm.Session, kind int, amount float64, title string, chain *model.BlockStarChain) error {
now := time.Now()
var blockStarChainFlow model.BlockStarChainFlow
blockStarChainFlow.CoinId = chain.Coin1
blockStarChainFlow.Direction = md.FlowDirectionIncome
blockStarChainFlow.Kind = kind
blockStarChainFlow.Title = title
blockStarChainFlow.CreateTime = now
switch kind {
case int(enum.SystemTimingIssue):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) - amount)
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = chain.TotalDestroyCoin
break
}
chain.TotalNowCoin = blockStarChainFlow.AfterTotalNowCoin
chain.TotalRemainderCoin = blockStarChainFlow.AfterTotalRemainderCoin
chain.TotalPublishCoin = blockStarChainFlow.AfterTotalPublishCoin
chain.TotalDestroyCoin = blockStarChainFlow.AfterTotalDestroyCoin

//更新 `block_star_chain` 表
updateAffected, err := db.BlockStarChainUpdate(session, chain.Id, chain)
if err != nil {
return err
}
if updateAffected == 0 {
err = errors.New("更新 block_star_chain 记录失败")
return err
}

//插入 `block_star_chain_flow` 记录
_, err = db.BlockStarChainFlowInsert(session, &blockStarChainFlow)
if err != nil {
return err
}
return nil
}

//DealDestroyCoin 处理虚拟币 - 销毁
func DealDestroyCoin(session *xorm.Session, kind int, amount float64, title string, chain *model.BlockStarChain) error {
now := time.Now()
var blockStarChainFlow model.BlockStarChainFlow
blockStarChainFlow.CoinId = chain.Coin1
blockStarChainFlow.Direction = md.FlowDirectionExpenditure
blockStarChainFlow.Kind = kind
blockStarChainFlow.Title = title
blockStarChainFlow.CreateTime = now
switch kind {
case int(enum.SystemDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) - amount)
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.StaticUnallocatedAndDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.DynamicallyUnallocatedAndDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.OperationCenterUnallocatedAndDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.OtherUnallocatedAndDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.RewardDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.RewardUnallocatedAndDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.GroupLotteryAndDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.RedEnvelopeTransferBalanceAndDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
case int(enum.GroupLotteryAndDestroy):
blockStarChainFlow.BeforeTotalNowCoin = chain.TotalNowCoin
blockStarChainFlow.AfterTotalNowCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalNowCoin) - amount)
blockStarChainFlow.BeforeTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.AfterTotalRemainderCoin = chain.TotalRemainderCoin
blockStarChainFlow.BeforeTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.AfterTotalPublishCoin = chain.TotalPublishCoin
blockStarChainFlow.BeforeTotalDestroyCoin = chain.TotalDestroyCoin
blockStarChainFlow.AfterTotalDestroyCoin = zhios_order_relate_utils.Float64ToStrPrec10(zhios_order_relate_utils.StrToFloat64(chain.TotalRemainderCoin) + amount)
break
}
chain.TotalNowCoin = blockStarChainFlow.AfterTotalNowCoin
chain.TotalRemainderCoin = blockStarChainFlow.AfterTotalRemainderCoin
chain.TotalPublishCoin = blockStarChainFlow.AfterTotalPublishCoin
chain.TotalDestroyCoin = blockStarChainFlow.AfterTotalDestroyCoin
//更新 `block_star_chain` 表
updateAffected, err := db.BlockStarChainUpdate(session, chain.Id, chain)
if err != nil {
return err
}
if updateAffected == 0 {
err = errors.New("更新 block_star_chain 记录失败")
return err
}

//插入 `block_star_chain_flow` 记录
_, err = db.BlockStarChainFlowInsert(session, &blockStarChainFlow)
if err != nil {
return err
}
return nil
}

// DealUserCoin 处理给用户虚拟币积分
func DealUserCoin(session *xorm.Session, req md.DealUserCoinReq) (err error) {
//1、分布式锁阻拦
requestIdPrefix := fmt.Sprintf(md.DealUserCoinRequestIdPrefix, req.Mid, req.CoinId, req.Uid)
cb, err := svc.HandleDistributedLock(req.Mid, strconv.Itoa(req.Uid), requestIdPrefix)
if err != nil {
return err
}
if cb != nil {
defer cb() // 释放锁
}

//2、计算&&组装数据
now := time.Now()
coinAmount, err := svc.GetUserCoinAmount(session, req.Mid, req.CoinId, req.Uid)
if err != nil {
return
}
coinAmountValue := decimal.NewFromFloat(zhios_order_relate_utils.StrToFloat64(coinAmount))
amountValue := decimal.NewFromFloat(req.Amount)

var userVirtualCoinFlow model.UserVirtualCoinFlow
userVirtualCoinFlow.CoinId = req.CoinId
userVirtualCoinFlow.Title = req.Title
userVirtualCoinFlow.TransferType = req.TransferType
userVirtualCoinFlow.Uid = req.Uid
userVirtualCoinFlow.Amout = amountValue.String()
userVirtualCoinFlow.CreateTime = now

if req.Kind == "add" {
userVirtualCoinFlow.Direction = 1
userVirtualCoinFlow.AfterAmout = coinAmountValue.Add(amountValue).String()
} else if req.Kind == "sub" {
userVirtualCoinFlow.Direction = 2
userVirtualCoinFlow.AfterAmout = coinAmountValue.Sub(amountValue).String()
} else {
err = errors.New("错误的kind类型")
return
}

//3、插入 `user_virtual_coin_flow` 记录
_, err = db.UserVirtualCoinFlowInsert(session, &userVirtualCoinFlow)
if err != nil {
return err
}

//4、修改 `user_virtual_amount`的amount值 && 及缓存
err = svc.SetCacheUserVirtualAmount(session, req.Mid, userVirtualCoinFlow.AfterAmout, req.CoinId, req.Uid, true)
if err != nil {
return err
}

return nil
}

+ 60
- 0
svc/svc_block_star_chain_settlement.go View File

@@ -0,0 +1,60 @@
package svc

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/db/model"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/md"
zhios_order_relate_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/cache"
"fmt"
"xorm.io/xorm"
)

// GetUserCoinAmount 获取用户虚拟积分余额
func GetUserCoinAmount(session *xorm.Session, masterId string, coinId, uid int) (amount string, err error) {
redisKey := fmt.Sprintf(md.UserVirtualAmountRedisKey, masterId, coinId, uid)
amount, err = cache.GetString(redisKey)
if err != nil {
if err.Error() == "redigo: nil returned" {
if err != nil {
return amount, err
}
userVirtualAmount, err := db.GetUserVirtualWalletWithSession(session, uid, coinId)
if err != nil {
return amount, err
}
if userVirtualAmount == nil {
amount = "0"
} else {
amount = userVirtualAmount.Amount
}
//将获取到的余额值缓存至redis
_ = SetCacheUserVirtualAmount(session, masterId, amount, coinId, uid, false)
return amount, nil
}
return amount, err
}
return amount, nil
}

// SetCacheUserVirtualAmount 设置缓存的用户虚拟币积分余额
func SetCacheUserVirtualAmount(session *xorm.Session, masterId, amount string, coinId, uid int, isUpdateDb bool) error {
redisKey := fmt.Sprintf(md.UserVirtualAmountRedisKey, masterId, coinId, uid)
if isUpdateDb {
_, err := session.Where("uid=?", uid).And("coin_id=?", coinId).Update(model.UserVirtualAmount{
Uid: uid,
CoinId: coinId,
Amount: amount,
})
if err != nil {
return err
}
}
//_, err := cache.Set(redisKey, int64(utils.StrToFloat64(amount)))
//TODO::默认缓存1小时 (先调整为 10 min)
_, err := cache.SetEx(redisKey, int64(zhios_order_relate_utils.StrToFloat64(amount)), 60*60*0.1)
if err != nil {
return err
}
return nil
}

+ 84
- 0
svc/svc_redis_mutex_lock.go View File

@@ -0,0 +1,84 @@
package svc

import (
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/md"
zhios_order_relate_utils "code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils"
"code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git/utils/cache"
"errors"
"fmt"
"math/rand"
"reflect"
"time"
)

const redisMutexLockExpTime = 15

// TryGetDistributedLock 分布式锁获取
// requestId 用于标识请求客户端,可以是随机字符串,需确保唯一
func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool {
if isNegative { // 多次尝试获取
retry := 1
for {
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX")
// 获取锁成功
if err == nil && ok == "OK" {
return true
}
// 尝试多次没获取成功
if retry > 10 {
return false
}
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000)))
retry += 1
}
} else { // 只尝试一次
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX")
// 获取锁成功
if err == nil && ok == "OK" {
return true
}

return false
}
}

// ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型
func ReleaseDistributedLock(lockKey, requestId string) (bool, error) {
luaScript := `
if redis.call("get",KEYS[1]) == ARGV[1]
then
return redis.call("del",KEYS[1])
else
return 0
end`

do, err := cache.Do("eval", luaScript, 1, lockKey, requestId)
fmt.Println(reflect.TypeOf(do))
fmt.Println(do)
if zhios_order_relate_utils.AnyToInt64(do) == 1 {
return true, err
} else {
return false, err
}
}

func GetDistributedLockRequestId(prefix string) string {
return prefix + zhios_order_relate_utils.IntToStr(rand.Intn(100000000))
}

// HandleDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁
func HandleDistributedLock(masterId, uid, requestIdPrefix string) (cb func(), err error) {
// 获取余额更新锁
balanceLockKey := fmt.Sprintf(md.UserFinValidUpdateLock, masterId, uid)
requestId := GetDistributedLockRequestId(requestIdPrefix)
balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true)
if !balanceLockOk {
return nil, errors.New("系统繁忙,请稍后再试")
}

cb = func() {
_, _ = ReleaseDistributedLock(balanceLockKey, requestId)
}

return cb, nil
}

+ 421
- 0
utils/cache/base.go View File

@@ -0,0 +1,421 @@
package cache

import (
"errors"
"fmt"
"strconv"
"time"
)

const (
redisDialTTL = 10 * time.Second
redisReadTTL = 3 * time.Second
redisWriteTTL = 3 * time.Second
redisIdleTTL = 10 * time.Second
redisPoolTTL = 10 * time.Second
redisPoolSize int = 512
redisMaxIdleConn int = 64
redisMaxActive int = 512
)

var (
ErrNil = errors.New("nil return")
ErrWrongArgsNum = errors.New("args num error")
ErrNegativeInt = errors.New("redis cluster: unexpected value for Uint64")
)

// 以下为提供类型转换

func Int(reply interface{}, err error) (int, error) {
if err != nil {
return 0, err
}
switch reply := reply.(type) {
case int:
return reply, nil
case int8:
return int(reply), nil
case int16:
return int(reply), nil
case int32:
return int(reply), nil
case int64:
x := int(reply)
if int64(x) != reply {
return 0, strconv.ErrRange
}
return x, nil
case uint:
n := int(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case uint8:
return int(reply), nil
case uint16:
return int(reply), nil
case uint32:
n := int(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case uint64:
n := int(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case []byte:
data := string(reply)
if len(data) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseInt(data, 10, 0)
return int(n), err
case string:
if len(reply) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseInt(reply, 10, 0)
return int(n), err
case nil:
return 0, ErrNil
case error:
return 0, reply
}
return 0, fmt.Errorf("redis cluster: unexpected type for Int, got type %T", reply)
}

func Int64(reply interface{}, err error) (int64, error) {
if err != nil {
return 0, err
}
switch reply := reply.(type) {
case int:
return int64(reply), nil
case int8:
return int64(reply), nil
case int16:
return int64(reply), nil
case int32:
return int64(reply), nil
case int64:
return reply, nil
case uint:
n := int64(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case uint8:
return int64(reply), nil
case uint16:
return int64(reply), nil
case uint32:
return int64(reply), nil
case uint64:
n := int64(reply)
if n < 0 {
return 0, strconv.ErrRange
}
return n, nil
case []byte:
data := string(reply)
if len(data) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseInt(data, 10, 64)
return n, err
case string:
if len(reply) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseInt(reply, 10, 64)
return n, err
case nil:
return 0, ErrNil
case error:
return 0, reply
}
return 0, fmt.Errorf("redis cluster: unexpected type for Int64, got type %T", reply)
}

func Uint64(reply interface{}, err error) (uint64, error) {
if err != nil {
return 0, err
}
switch reply := reply.(type) {
case uint:
return uint64(reply), nil
case uint8:
return uint64(reply), nil
case uint16:
return uint64(reply), nil
case uint32:
return uint64(reply), nil
case uint64:
return reply, nil
case int:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case int8:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case int16:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case int32:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case int64:
if reply < 0 {
return 0, ErrNegativeInt
}
return uint64(reply), nil
case []byte:
data := string(reply)
if len(data) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseUint(data, 10, 64)
return n, err
case string:
if len(reply) == 0 {
return 0, ErrNil
}

n, err := strconv.ParseUint(reply, 10, 64)
return n, err
case nil:
return 0, ErrNil
case error:
return 0, reply
}
return 0, fmt.Errorf("redis cluster: unexpected type for Uint64, got type %T", reply)
}

func Float64(reply interface{}, err error) (float64, error) {
if err != nil {
return 0, err
}

var value float64
err = nil
switch v := reply.(type) {
case float32:
value = float64(v)
case float64:
value = v
case int:
value = float64(v)
case int8:
value = float64(v)
case int16:
value = float64(v)
case int32:
value = float64(v)
case int64:
value = float64(v)
case uint:
value = float64(v)
case uint8:
value = float64(v)
case uint16:
value = float64(v)
case uint32:
value = float64(v)
case uint64:
value = float64(v)
case []byte:
data := string(v)
if len(data) == 0 {
return 0, ErrNil
}
value, err = strconv.ParseFloat(string(v), 64)
case string:
if len(v) == 0 {
return 0, ErrNil
}
value, err = strconv.ParseFloat(v, 64)
case nil:
err = ErrNil
case error:
err = v
default:
err = fmt.Errorf("redis cluster: unexpected type for Float64, got type %T", v)
}

return value, err
}

func Bool(reply interface{}, err error) (bool, error) {
if err != nil {
return false, err
}
switch reply := reply.(type) {
case bool:
return reply, nil
case int64:
return reply != 0, nil
case []byte:
data := string(reply)
if len(data) == 0 {
return false, ErrNil
}

return strconv.ParseBool(data)
case string:
if len(reply) == 0 {
return false, ErrNil
}

return strconv.ParseBool(reply)
case nil:
return false, ErrNil
case error:
return false, reply
}
return false, fmt.Errorf("redis cluster: unexpected type for Bool, got type %T", reply)
}

func Bytes(reply interface{}, err error) ([]byte, error) {
if err != nil {
return nil, err
}
switch reply := reply.(type) {
case []byte:
if len(reply) == 0 {
return nil, ErrNil
}
return reply, nil
case string:
data := []byte(reply)
if len(data) == 0 {
return nil, ErrNil
}
return data, nil
case nil:
return nil, ErrNil
case error:
return nil, reply
}
return nil, fmt.Errorf("redis cluster: unexpected type for Bytes, got type %T", reply)
}

func String(reply interface{}, err error) (string, error) {
if err != nil {
return "", err
}

value := ""
err = nil
switch v := reply.(type) {
case string:
if len(v) == 0 {
return "", ErrNil
}

value = v
case []byte:
if len(v) == 0 {
return "", ErrNil
}

value = string(v)
case int:
value = strconv.FormatInt(int64(v), 10)
case int8:
value = strconv.FormatInt(int64(v), 10)
case int16:
value = strconv.FormatInt(int64(v), 10)
case int32:
value = strconv.FormatInt(int64(v), 10)
case int64:
value = strconv.FormatInt(v, 10)
case uint:
value = strconv.FormatUint(uint64(v), 10)
case uint8:
value = strconv.FormatUint(uint64(v), 10)
case uint16:
value = strconv.FormatUint(uint64(v), 10)
case uint32:
value = strconv.FormatUint(uint64(v), 10)
case uint64:
value = strconv.FormatUint(v, 10)
case float32:
value = strconv.FormatFloat(float64(v), 'f', -1, 32)
case float64:
value = strconv.FormatFloat(v, 'f', -1, 64)
case bool:
value = strconv.FormatBool(v)
case nil:
err = ErrNil
case error:
err = v
default:
err = fmt.Errorf("redis cluster: unexpected type for String, got type %T", v)
}

return value, err
}

func Strings(reply interface{}, err error) ([]string, error) {
if err != nil {
return nil, err
}
switch reply := reply.(type) {
case []interface{}:
result := make([]string, len(reply))
for i := range reply {
if reply[i] == nil {
continue
}
switch subReply := reply[i].(type) {
case string:
result[i] = subReply
case []byte:
result[i] = string(subReply)
default:
return nil, fmt.Errorf("redis cluster: unexpected element type for String, got type %T", reply[i])
}
}
return result, nil
case []string:
return reply, nil
case nil:
return nil, ErrNil
case error:
return nil, reply
}
return nil, fmt.Errorf("redis cluster: unexpected type for Strings, got type %T", reply)
}

func Values(reply interface{}, err error) ([]interface{}, error) {
if err != nil {
return nil, err
}
switch reply := reply.(type) {
case []interface{}:
return reply, nil
case nil:
return nil, ErrNil
case error:
return nil, reply
}
return nil, fmt.Errorf("redis cluster: unexpected type for Values, got type %T", reply)
}

+ 413
- 0
utils/cache/redis.go View File

@@ -0,0 +1,413 @@
package cache

import (
"encoding/json"
"errors"
"log"
"strings"
"time"

redigo "github.com/gomodule/redigo/redis"
)

// configuration
type Config struct {
Server string
Password string
MaxIdle int // Maximum number of idle connections in the pool.

// Maximum number of connections allocated by the pool at a given time.
// When zero, there is no limit on the number of connections in the pool.
MaxActive int

// Close connections after remaining idle for this duration. If the value
// is zero, then idle connections are not closed. Applications should set
// the timeout to a value less than the server's timeout.
IdleTimeout time.Duration

// If Wait is true and the pool is at the MaxActive limit, then Get() waits
// for a connection to be returned to the pool before returning.
Wait bool
KeyPrefix string // prefix to all keys; example is "dev environment name"
KeyDelimiter string // delimiter to be used while appending keys; example is ":"
KeyPlaceholder string // placeholder to be parsed using given arguments to obtain a final key; example is "?"
}

var pool *redigo.Pool
var conf *Config

func NewRedis(addr string) {
if addr == "" {
panic("\nredis connect string cannot be empty\n")
}
pool = &redigo.Pool{
MaxIdle: redisMaxIdleConn,
IdleTimeout: redisIdleTTL,
MaxActive: redisMaxActive,
// MaxConnLifetime: redisDialTTL,
Wait: true,
Dial: func() (redigo.Conn, error) {
c, err := redigo.Dial("tcp", addr,
redigo.DialConnectTimeout(redisDialTTL),
redigo.DialReadTimeout(redisReadTTL),
redigo.DialWriteTimeout(redisWriteTTL),
//redigo.DialDatabase(RedisDataBase),
)
if err != nil {
log.Println("Redis Dial failed: ", err)
return nil, err
}
return c, err
},
TestOnBorrow: func(c redigo.Conn, t time.Time) error {
_, err := c.Do("PING")
if err != nil {
log.Println("Unable to ping to redis server:", err)
}
return err
},
}
conn := pool.Get()
defer conn.Close()
if conn.Err() != nil {
println("\nredis connect " + addr + " error: " + conn.Err().Error())
} else {
println("\nredis connect " + addr + " success!\n")
}
}

func Do(cmd string, args ...interface{}) (reply interface{}, err error) {
conn := pool.Get()
defer conn.Close()
return conn.Do(cmd, args...)
}

func SelectDb(db int) (interface{}, error) {
return Do("SELECT", db)
}

func GetPool() *redigo.Pool {
return pool
}

func ParseKey(key string, vars []string) (string, error) {
arr := strings.Split(key, conf.KeyPlaceholder)
actualKey := ""
if len(arr) != len(vars)+1 {
return "", errors.New("redis/connection.go: Insufficient arguments to parse key")
} else {
for index, val := range arr {
if index == 0 {
actualKey = arr[index]
} else {
actualKey += vars[index-1] + val
}
}
}
return getPrefixedKey(actualKey), nil
}

func getPrefixedKey(key string) string {
return conf.KeyPrefix + conf.KeyDelimiter + key
}
func StripEnvKey(key string) string {
return strings.TrimLeft(key, conf.KeyPrefix+conf.KeyDelimiter)
}
func SplitKey(key string) []string {
return strings.Split(key, conf.KeyDelimiter)
}
func Expire(key string, ttl int) (interface{}, error) {
return Do("EXPIRE", key, ttl)
}
func Persist(key string) (interface{}, error) {
return Do("PERSIST", key)
}

func Del(key string) (interface{}, error) {
return Do("DEL", key)
}
func Set(key string, data interface{}) (interface{}, error) {
// set
return Do("SET", key, data)
}
func SetNX(key string, data interface{}) (interface{}, error) {
return Do("SETNX", key, data)
}
func SetEx(key string, data interface{}, ttl int) (interface{}, error) {
return Do("SETEX", key, ttl, data)
}

func SetJson(key string, data interface{}, ttl int) bool {
c, err := json.Marshal(data)
if err != nil {
return false
}
if ttl < 1 {
_, err = Set(key, c)
} else {
_, err = SetEx(key, c, ttl)
}
if err != nil {
return false
}
return true
}

func GetJson(key string, dst interface{}) error {
b, err := GetBytes(key)
if err != nil {
return err
}
if err = json.Unmarshal(b, dst); err != nil {
return err
}
return nil
}

func Get(key string) (interface{}, error) {
// get
return Do("GET", key)
}
func GetTTL(key string) (time.Duration, error) {
ttl, err := redigo.Int64(Do("TTL", key))
return time.Duration(ttl) * time.Second, err
}
func GetBytes(key string) ([]byte, error) {
return redigo.Bytes(Do("GET", key))
}
func GetString(key string) (string, error) {
return redigo.String(Do("GET", key))
}
func GetStringMap(key string) (map[string]string, error) {
return redigo.StringMap(Do("GET", key))
}
func GetInt(key string) (int, error) {
return redigo.Int(Do("GET", key))
}
func GetInt64(key string) (int64, error) {
return redigo.Int64(Do("GET", key))
}
func GetStringLength(key string) (int, error) {
return redigo.Int(Do("STRLEN", key))
}
func ZAdd(key string, score float64, data interface{}) (interface{}, error) {
return Do("ZADD", key, score, data)
}
func ZAddNX(key string, score float64, data interface{}) (interface{}, error) {
return Do("ZADD", key, "NX", score, data)
}
func ZRem(key string, data interface{}) (interface{}, error) {
return Do("ZREM", key, data)
}
func ZRange(key string, start int, end int, withScores bool) ([]interface{}, error) {
if withScores {
return redigo.Values(Do("ZRANGE", key, start, end, "WITHSCORES"))
}
return redigo.Values(Do("ZRANGE", key, start, end))
}
func ZRemRangeByScore(key string, start int64, end int64) ([]interface{}, error) {
return redigo.Values(Do("ZREMRANGEBYSCORE", key, start, end))
}
func ZCard(setName string) (int64, error) {
return redigo.Int64(Do("ZCARD", setName))
}
func ZScan(setName string) (int64, error) {
return redigo.Int64(Do("ZCARD", setName))
}
func SAdd(setName string, data interface{}) (interface{}, error) {
return Do("SADD", setName, data)
}
func SCard(setName string) (int64, error) {
return redigo.Int64(Do("SCARD", setName))
}
func SIsMember(setName string, data interface{}) (bool, error) {
return redigo.Bool(Do("SISMEMBER", setName, data))
}
func SMembers(setName string) ([]string, error) {
return redigo.Strings(Do("SMEMBERS", setName))
}
func SRem(setName string, data interface{}) (interface{}, error) {
return Do("SREM", setName, data)
}
func HSet(key string, HKey string, data interface{}) (interface{}, error) {
return Do("HSET", key, HKey, data)
}

func HGet(key string, HKey string) (interface{}, error) {
return Do("HGET", key, HKey)
}

func HMGet(key string, hashKeys ...string) ([]interface{}, error) {
ret, err := Do("HMGET", key, hashKeys)
if err != nil {
return nil, err
}
reta, ok := ret.([]interface{})
if !ok {
return nil, errors.New("result not an array")
}
return reta, nil
}

func HMSet(key string, hashKeys []string, vals []interface{}) (interface{}, error) {
if len(hashKeys) == 0 || len(hashKeys) != len(vals) {
var ret interface{}
return ret, errors.New("bad length")
}
input := []interface{}{key}
for i, v := range hashKeys {
input = append(input, v, vals[i])
}
return Do("HMSET", input...)
}

func HGetString(key string, HKey string) (string, error) {
return redigo.String(Do("HGET", key, HKey))
}
func HGetFloat(key string, HKey string) (float64, error) {
f, err := redigo.Float64(Do("HGET", key, HKey))
return f, err
}
func HGetInt(key string, HKey string) (int, error) {
return redigo.Int(Do("HGET", key, HKey))
}
func HGetInt64(key string, HKey string) (int64, error) {
return redigo.Int64(Do("HGET", key, HKey))
}
func HGetBool(key string, HKey string) (bool, error) {
return redigo.Bool(Do("HGET", key, HKey))
}
func HDel(key string, HKey string) (interface{}, error) {
return Do("HDEL", key, HKey)
}

func HGetAll(key string) (map[string]interface{}, error) {
vals, err := redigo.Values(Do("HGETALL", key))
if err != nil {
return nil, err
}
num := len(vals) / 2
result := make(map[string]interface{}, num)
for i := 0; i < num; i++ {
key, _ := redigo.String(vals[2*i], nil)
result[key] = vals[2*i+1]
}
return result, nil
}

func FlushAll() bool {
res, _ := redigo.String(Do("FLUSHALL"))
if res == "" {
return false
}
return true
}

// NOTE: Use this in production environment with extreme care.
// Read more here:https://redigo.io/commands/keys
func Keys(pattern string) ([]string, error) {
return redigo.Strings(Do("KEYS", pattern))
}

func HKeys(key string) ([]string, error) {
return redigo.Strings(Do("HKEYS", key))
}

func Exists(key string) bool {
count, err := redigo.Int(Do("EXISTS", key))
if count == 0 || err != nil {
return false
}
return true
}

func Incr(key string) (int64, error) {
return redigo.Int64(Do("INCR", key))
}

func Decr(key string) (int64, error) {
return redigo.Int64(Do("DECR", key))
}

func IncrBy(key string, incBy int64) (int64, error) {
return redigo.Int64(Do("INCRBY", key, incBy))
}

func DecrBy(key string, decrBy int64) (int64, error) {
return redigo.Int64(Do("DECRBY", key, decrBy))
}

func IncrByFloat(key string, incBy float64) (float64, error) {
return redigo.Float64(Do("INCRBYFLOAT", key, incBy))
}

func DecrByFloat(key string, decrBy float64) (float64, error) {
return redigo.Float64(Do("DECRBYFLOAT", key, decrBy))
}

// use for message queue
func LPush(key string, data interface{}) (interface{}, error) {
// set
return Do("LPUSH", key, data)
}

func LPop(key string) (interface{}, error) {
return Do("LPOP", key)
}

func LPopString(key string) (string, error) {
return redigo.String(Do("LPOP", key))
}
func LPopFloat(key string) (float64, error) {
f, err := redigo.Float64(Do("LPOP", key))
return f, err
}
func LPopInt(key string) (int, error) {
return redigo.Int(Do("LPOP", key))
}
func LPopInt64(key string) (int64, error) {
return redigo.Int64(Do("LPOP", key))
}

func RPush(key string, data interface{}) (interface{}, error) {
// set
return Do("RPUSH", key, data)
}

func RPop(key string) (interface{}, error) {
return Do("RPOP", key)
}

func RPopString(key string) (string, error) {
return redigo.String(Do("RPOP", key))
}
func RPopFloat(key string) (float64, error) {
f, err := redigo.Float64(Do("RPOP", key))
return f, err
}
func RPopInt(key string) (int, error) {
return redigo.Int(Do("RPOP", key))
}
func RPopInt64(key string) (int64, error) {
return redigo.Int64(Do("RPOP", key))
}

func Scan(cursor int64, pattern string, count int64) (int64, []string, error) {
var items []string
var newCursor int64

values, err := redigo.Values(Do("SCAN", cursor, "MATCH", pattern, "COUNT", count))
if err != nil {
return 0, nil, err
}
values, err = redigo.Scan(values, &newCursor, &items)
if err != nil {
return 0, nil, err
}
return newCursor, items, nil
}

func LPushMax(key string, data ...interface{}) (interface{}, error) {
// set
return Do("LPUSH", key, data)
}

+ 622
- 0
utils/cache/redis_cluster.go View File

@@ -0,0 +1,622 @@
package cache

import (
"strconv"
"time"

"github.com/go-redis/redis"
)

var pools *redis.ClusterClient

func NewRedisCluster(addrs []string) error {
opt := &redis.ClusterOptions{
Addrs: addrs,
PoolSize: redisPoolSize,
PoolTimeout: redisPoolTTL,
IdleTimeout: redisIdleTTL,
DialTimeout: redisDialTTL,
ReadTimeout: redisReadTTL,
WriteTimeout: redisWriteTTL,
}
pools = redis.NewClusterClient(opt)
if err := pools.Ping().Err(); err != nil {
return err
}
return nil
}

func RCGet(key string) (interface{}, error) {
res, err := pools.Get(key).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func RCSet(key string, value interface{}) error {
err := pools.Set(key, value, 0).Err()
return convertError(err)
}
func RCGetSet(key string, value interface{}) (interface{}, error) {
res, err := pools.GetSet(key, value).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func RCSetNx(key string, value interface{}) (int64, error) {
res, err := pools.SetNX(key, value, 0).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func RCSetEx(key string, value interface{}, timeout int64) error {
_, err := pools.Set(key, value, time.Duration(timeout)*time.Second).Result()
if err != nil {
return convertError(err)
}
return nil
}

// nil表示成功,ErrNil表示数据库内已经存在这个key,其他表示数据库发生错误
func RCSetNxEx(key string, value interface{}, timeout int64) error {
res, err := pools.SetNX(key, value, time.Duration(timeout)*time.Second).Result()
if err != nil {
return convertError(err)
}
if res {
return nil
}
return ErrNil
}
func RCMGet(keys ...string) ([]interface{}, error) {
res, err := pools.MGet(keys...).Result()
return res, convertError(err)
}

// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test}
func RCMSet(kvs map[string]interface{}) error {
pairs := make([]string, 0, len(kvs)*2)
for k, v := range kvs {
val, err := String(v, nil)
if err != nil {
return err
}
pairs = append(pairs, k, val)
}
return convertError(pools.MSet(pairs).Err())
}

// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test}
func RCMSetNX(kvs map[string]interface{}) (bool, error) {
pairs := make([]string, 0, len(kvs)*2)
for k, v := range kvs {
val, err := String(v, nil)
if err != nil {
return false, err
}
pairs = append(pairs, k, val)
}
res, err := pools.MSetNX(pairs).Result()
return res, convertError(err)
}
func RCExpireAt(key string, timestamp int64) (int64, error) {
res, err := pools.ExpireAt(key, time.Unix(timestamp, 0)).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func RCDel(keys ...string) (int64, error) {
args := make([]interface{}, 0, len(keys))
for _, key := range keys {
args = append(args, key)
}
res, err := pools.Del(keys...).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCIncr(key string) (int64, error) {
res, err := pools.Incr(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCIncrBy(key string, delta int64) (int64, error) {
res, err := pools.IncrBy(key, delta).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCExpire(key string, duration int64) (int64, error) {
res, err := pools.Expire(key, time.Duration(duration)*time.Second).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func RCExists(key string) (bool, error) {
res, err := pools.Exists(key).Result()
if err != nil {
return false, convertError(err)
}
if res > 0 {
return true, nil
}
return false, nil
}
func RCHGet(key string, field string) (interface{}, error) {
res, err := pools.HGet(key, field).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func RCHLen(key string) (int64, error) {
res, err := pools.HLen(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCHSet(key string, field string, val interface{}) error {
value, err := String(val, nil)
if err != nil && err != ErrNil {
return err
}
_, err = pools.HSet(key, field, value).Result()
if err != nil {
return convertError(err)
}
return nil
}
func RCHDel(key string, fields ...string) (int64, error) {
args := make([]interface{}, 0, len(fields)+1)
args = append(args, key)
for _, field := range fields {
args = append(args, field)
}
res, err := pools.HDel(key, fields...).Result()
if err != nil {
return 0, convertError(err)
}
return res, nil
}

func RCHMGet(key string, fields ...string) (interface{}, error) {
args := make([]interface{}, 0, len(fields)+1)
args = append(args, key)
for _, field := range fields {
args = append(args, field)
}
if len(fields) == 0 {
return nil, ErrNil
}
res, err := pools.HMGet(key, fields...).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCHMSet(key string, kvs ...interface{}) error {
if len(kvs) == 0 {
return nil
}
if len(kvs)%2 != 0 {
return ErrWrongArgsNum
}
var err error
v := map[string]interface{}{} // todo change
v["field"], err = String(kvs[0], nil)
if err != nil && err != ErrNil {
return err
}
v["value"], err = String(kvs[1], nil)
if err != nil && err != ErrNil {
return err
}
pairs := make([]string, 0, len(kvs)-2)
if len(kvs) > 2 {
for _, kv := range kvs[2:] {
kvString, err := String(kv, nil)
if err != nil && err != ErrNil {
return err
}
pairs = append(pairs, kvString)
}
}
v["paris"] = pairs
_, err = pools.HMSet(key, v).Result()
if err != nil {
return convertError(err)
}
return nil
}

func RCHKeys(key string) ([]string, error) {
res, err := pools.HKeys(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCHVals(key string) ([]interface{}, error) {
res, err := pools.HVals(key).Result()
if err != nil {
return nil, convertError(err)
}
rs := make([]interface{}, 0, len(res))
for _, res := range res {
rs = append(rs, res)
}
return rs, nil
}
func RCHGetAll(key string) (map[string]string, error) {
vals, err := pools.HGetAll(key).Result()
if err != nil {
return nil, convertError(err)
}
return vals, nil
}
func RCHIncrBy(key, field string, delta int64) (int64, error) {
res, err := pools.HIncrBy(key, field, delta).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCZAdd(key string, kvs ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(kvs)+1)
args = append(args, key)
args = append(args, kvs...)
if len(kvs) == 0 {
return 0, nil
}
if len(kvs)%2 != 0 {
return 0, ErrWrongArgsNum
}
zs := make([]redis.Z, len(kvs)/2)
for i := 0; i < len(kvs); i += 2 {
idx := i / 2
score, err := Float64(kvs[i], nil)
if err != nil && err != ErrNil {
return 0, err
}
zs[idx].Score = score
zs[idx].Member = kvs[i+1]
}
res, err := pools.ZAdd(key, zs...).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCZRem(key string, members ...string) (int64, error) {
args := make([]interface{}, 0, len(members))
args = append(args, key)
for _, member := range members {
args = append(args, member)
}
res, err := pools.ZRem(key, members).Result()
if err != nil {
return res, convertError(err)
}
return res, err
}

func RCZRange(key string, min, max int64, withScores bool) (interface{}, error) {
res := make([]interface{}, 0)
if withScores {
zs, err := pools.ZRangeWithScores(key, min, max).Result()
if err != nil {
return nil, convertError(err)
}
for _, z := range zs {
res = append(res, z.Member, strconv.FormatFloat(z.Score, 'f', -1, 64))
}
} else {
ms, err := pools.ZRange(key, min, max).Result()
if err != nil {
return nil, convertError(err)
}
for _, m := range ms {
res = append(res, m)
}
}
return res, nil
}
func RCZRangeByScoreWithScore(key string, min, max int64) (map[string]int64, error) {
opt := new(redis.ZRangeBy)
opt.Min = strconv.FormatInt(int64(min), 10)
opt.Max = strconv.FormatInt(int64(max), 10)
opt.Count = -1
opt.Offset = 0
vals, err := pools.ZRangeByScoreWithScores(key, *opt).Result()
if err != nil {
return nil, convertError(err)
}
res := make(map[string]int64, len(vals))
for _, val := range vals {
key, err := String(val.Member, nil)
if err != nil && err != ErrNil {
return nil, err
}
res[key] = int64(val.Score)
}
return res, nil
}
func RCLRange(key string, start, stop int64) (interface{}, error) {
res, err := pools.LRange(key, start, stop).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCLSet(key string, index int, value interface{}) error {
err := pools.LSet(key, int64(index), value).Err()
return convertError(err)
}
func RCLLen(key string) (int64, error) {
res, err := pools.LLen(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCLRem(key string, count int, value interface{}) (int, error) {
val, _ := value.(string)
res, err := pools.LRem(key, int64(count), val).Result()
if err != nil {
return int(res), convertError(err)
}
return int(res), nil
}
func RCTTl(key string) (int64, error) {
duration, err := pools.TTL(key).Result()
if err != nil {
return int64(duration.Seconds()), convertError(err)
}
return int64(duration.Seconds()), nil
}
func RCLPop(key string) (interface{}, error) {
res, err := pools.LPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCRPop(key string) (interface{}, error) {
res, err := pools.RPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCBLPop(key string, timeout int) (interface{}, error) {
res, err := pools.BLPop(time.Duration(timeout)*time.Second, key).Result()
if err != nil {
// 兼容redis 2.x
if err == redis.Nil {
return nil, ErrNil
}
return nil, err
}
return res[1], nil
}
func RCBRPop(key string, timeout int) (interface{}, error) {
res, err := pools.BRPop(time.Duration(timeout)*time.Second, key).Result()
if err != nil {
// 兼容redis 2.x
if err == redis.Nil {
return nil, ErrNil
}
return nil, convertError(err)
}
return res[1], nil
}
func RCLPush(key string, value ...interface{}) error {
args := make([]interface{}, 0, len(value)+1)
args = append(args, key)
args = append(args, value...)
vals := make([]string, 0, len(value))
for _, v := range value {
val, err := String(v, nil)
if err != nil && err != ErrNil {
return err
}
vals = append(vals, val)
}
_, err := pools.LPush(key, vals).Result() // todo ...
if err != nil {
return convertError(err)
}
return nil
}
func RCRPush(key string, value ...interface{}) error {
args := make([]interface{}, 0, len(value)+1)
args = append(args, key)
args = append(args, value...)
vals := make([]string, 0, len(value))
for _, v := range value {
val, err := String(v, nil)
if err != nil && err != ErrNil {
if err == ErrNil {
continue
}
return err
}
if val == "" {
continue
}
vals = append(vals, val)
}
_, err := pools.RPush(key, vals).Result() // todo ...
if err != nil {
return convertError(err)
}
return nil
}

// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test}
func RCBRPopLPush(srcKey string, destKey string, timeout int) (interface{}, error) {
res, err := pools.BRPopLPush(srcKey, destKey, time.Duration(timeout)*time.Second).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}

// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test}
func RCRPopLPush(srcKey string, destKey string) (interface{}, error) {
res, err := pools.RPopLPush(srcKey, destKey).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCSAdd(key string, members ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(members)+1)
args = append(args, key)
args = append(args, members...)
ms := make([]string, 0, len(members))
for _, member := range members {
m, err := String(member, nil)
if err != nil && err != ErrNil {
return 0, err
}
ms = append(ms, m)
}
res, err := pools.SAdd(key, ms).Result() // todo ...
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCSPop(key string) ([]byte, error) {
res, err := pools.SPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func RCSIsMember(key string, member interface{}) (bool, error) {
m, _ := member.(string)
res, err := pools.SIsMember(key, m).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCSRem(key string, members ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(members)+1)
args = append(args, key)
args = append(args, members...)
ms := make([]string, 0, len(members))
for _, member := range members {
m, err := String(member, nil)
if err != nil && err != ErrNil {
return 0, err
}
ms = append(ms, m)
}
res, err := pools.SRem(key, ms).Result() // todo ...
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCSMembers(key string) ([]string, error) {
res, err := pools.SMembers(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCScriptLoad(luaScript string) (interface{}, error) {
res, err := pools.ScriptLoad(luaScript).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCEvalSha(sha1 string, numberKeys int, keysArgs ...interface{}) (interface{}, error) {
vals := make([]interface{}, 0, len(keysArgs)+2)
vals = append(vals, sha1, numberKeys)
vals = append(vals, keysArgs...)
keys := make([]string, 0, numberKeys)
args := make([]string, 0, len(keysArgs)-numberKeys)
for i, value := range keysArgs {
val, err := String(value, nil)
if err != nil && err != ErrNil {
return nil, err
}
if i < numberKeys {
keys = append(keys, val)
} else {
args = append(args, val)
}
}
res, err := pools.EvalSha(sha1, keys, args).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCEval(luaScript string, numberKeys int, keysArgs ...interface{}) (interface{}, error) {
vals := make([]interface{}, 0, len(keysArgs)+2)
vals = append(vals, luaScript, numberKeys)
vals = append(vals, keysArgs...)
keys := make([]string, 0, numberKeys)
args := make([]string, 0, len(keysArgs)-numberKeys)
for i, value := range keysArgs {
val, err := String(value, nil)
if err != nil && err != ErrNil {
return nil, err
}
if i < numberKeys {
keys = append(keys, val)
} else {
args = append(args, val)
}
}
res, err := pools.Eval(luaScript, keys, args).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func RCGetBit(key string, offset int64) (int64, error) {
res, err := pools.GetBit(key, offset).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func RCSetBit(key string, offset uint32, value int) (int, error) {
res, err := pools.SetBit(key, int64(offset), value).Result()
return int(res), convertError(err)
}
func RCGetClient() *redis.ClusterClient {
return pools
}
func convertError(err error) error {
if err == redis.Nil {
// 为了兼容redis 2.x,这里不返回 ErrNil,ErrNil在调用redis_cluster_reply函数时才返回
return nil
}
return err
}

+ 324
- 0
utils/cache/redis_pool.go View File

@@ -0,0 +1,324 @@
package cache

import (
"errors"
"log"
"strings"
"time"

redigo "github.com/gomodule/redigo/redis"
)

type RedisPool struct {
*redigo.Pool
}

func NewRedisPool(cfg *Config) *RedisPool {
return &RedisPool{&redigo.Pool{
MaxIdle: cfg.MaxIdle,
IdleTimeout: cfg.IdleTimeout,
MaxActive: cfg.MaxActive,
Wait: cfg.Wait,
Dial: func() (redigo.Conn, error) {
c, err := redigo.Dial("tcp", cfg.Server)
if err != nil {
log.Println("Redis Dial failed: ", err)
return nil, err
}
if cfg.Password != "" {
if _, err := c.Do("AUTH", cfg.Password); err != nil {
c.Close()
log.Println("Redis AUTH failed: ", err)
return nil, err
}
}
return c, err
},
TestOnBorrow: func(c redigo.Conn, t time.Time) error {
_, err := c.Do("PING")
if err != nil {
log.Println("Unable to ping to redis server:", err)
}
return err
},
}}
}

func (p *RedisPool) Do(cmd string, args ...interface{}) (reply interface{}, err error) {
conn := pool.Get()
defer conn.Close()
return conn.Do(cmd, args...)
}

func (p *RedisPool) GetPool() *redigo.Pool {
return pool
}

func (p *RedisPool) ParseKey(key string, vars []string) (string, error) {
arr := strings.Split(key, conf.KeyPlaceholder)
actualKey := ""
if len(arr) != len(vars)+1 {
return "", errors.New("redis/connection.go: Insufficient arguments to parse key")
} else {
for index, val := range arr {
if index == 0 {
actualKey = arr[index]
} else {
actualKey += vars[index-1] + val
}
}
}
return getPrefixedKey(actualKey), nil
}

func (p *RedisPool) getPrefixedKey(key string) string {
return conf.KeyPrefix + conf.KeyDelimiter + key
}
func (p *RedisPool) StripEnvKey(key string) string {
return strings.TrimLeft(key, conf.KeyPrefix+conf.KeyDelimiter)
}
func (p *RedisPool) SplitKey(key string) []string {
return strings.Split(key, conf.KeyDelimiter)
}
func (p *RedisPool) Expire(key string, ttl int) (interface{}, error) {
return Do("EXPIRE", key, ttl)
}
func (p *RedisPool) Persist(key string) (interface{}, error) {
return Do("PERSIST", key)
}

func (p *RedisPool) Del(key string) (interface{}, error) {
return Do("DEL", key)
}
func (p *RedisPool) Set(key string, data interface{}) (interface{}, error) {
// set
return Do("SET", key, data)
}
func (p *RedisPool) SetNX(key string, data interface{}) (interface{}, error) {
return Do("SETNX", key, data)
}
func (p *RedisPool) SetEx(key string, data interface{}, ttl int) (interface{}, error) {
return Do("SETEX", key, ttl, data)
}
func (p *RedisPool) Get(key string) (interface{}, error) {
// get
return Do("GET", key)
}
func (p *RedisPool) GetStringMap(key string) (map[string]string, error) {
// get
return redigo.StringMap(Do("GET", key))
}

func (p *RedisPool) GetTTL(key string) (time.Duration, error) {
ttl, err := redigo.Int64(Do("TTL", key))
return time.Duration(ttl) * time.Second, err
}
func (p *RedisPool) GetBytes(key string) ([]byte, error) {
return redigo.Bytes(Do("GET", key))
}
func (p *RedisPool) GetString(key string) (string, error) {
return redigo.String(Do("GET", key))
}
func (p *RedisPool) GetInt(key string) (int, error) {
return redigo.Int(Do("GET", key))
}
func (p *RedisPool) GetStringLength(key string) (int, error) {
return redigo.Int(Do("STRLEN", key))
}
func (p *RedisPool) ZAdd(key string, score float64, data interface{}) (interface{}, error) {
return Do("ZADD", key, score, data)
}
func (p *RedisPool) ZRem(key string, data interface{}) (interface{}, error) {
return Do("ZREM", key, data)
}
func (p *RedisPool) ZRange(key string, start int, end int, withScores bool) ([]interface{}, error) {
if withScores {
return redigo.Values(Do("ZRANGE", key, start, end, "WITHSCORES"))
}
return redigo.Values(Do("ZRANGE", key, start, end))
}
func (p *RedisPool) SAdd(setName string, data interface{}) (interface{}, error) {
return Do("SADD", setName, data)
}
func (p *RedisPool) SCard(setName string) (int64, error) {
return redigo.Int64(Do("SCARD", setName))
}
func (p *RedisPool) SIsMember(setName string, data interface{}) (bool, error) {
return redigo.Bool(Do("SISMEMBER", setName, data))
}
func (p *RedisPool) SMembers(setName string) ([]string, error) {
return redigo.Strings(Do("SMEMBERS", setName))
}
func (p *RedisPool) SRem(setName string, data interface{}) (interface{}, error) {
return Do("SREM", setName, data)
}
func (p *RedisPool) HSet(key string, HKey string, data interface{}) (interface{}, error) {
return Do("HSET", key, HKey, data)
}

func (p *RedisPool) HGet(key string, HKey string) (interface{}, error) {
return Do("HGET", key, HKey)
}

func (p *RedisPool) HMGet(key string, hashKeys ...string) ([]interface{}, error) {
ret, err := Do("HMGET", key, hashKeys)
if err != nil {
return nil, err
}
reta, ok := ret.([]interface{})
if !ok {
return nil, errors.New("result not an array")
}
return reta, nil
}

func (p *RedisPool) HMSet(key string, hashKeys []string, vals []interface{}) (interface{}, error) {
if len(hashKeys) == 0 || len(hashKeys) != len(vals) {
var ret interface{}
return ret, errors.New("bad length")
}
input := []interface{}{key}
for i, v := range hashKeys {
input = append(input, v, vals[i])
}
return Do("HMSET", input...)
}

func (p *RedisPool) HGetString(key string, HKey string) (string, error) {
return redigo.String(Do("HGET", key, HKey))
}
func (p *RedisPool) HGetFloat(key string, HKey string) (float64, error) {
f, err := redigo.Float64(Do("HGET", key, HKey))
return float64(f), err
}
func (p *RedisPool) HGetInt(key string, HKey string) (int, error) {
return redigo.Int(Do("HGET", key, HKey))
}
func (p *RedisPool) HGetInt64(key string, HKey string) (int64, error) {
return redigo.Int64(Do("HGET", key, HKey))
}
func (p *RedisPool) HGetBool(key string, HKey string) (bool, error) {
return redigo.Bool(Do("HGET", key, HKey))
}
func (p *RedisPool) HDel(key string, HKey string) (interface{}, error) {
return Do("HDEL", key, HKey)
}
func (p *RedisPool) HGetAll(key string) (map[string]interface{}, error) {
vals, err := redigo.Values(Do("HGETALL", key))
if err != nil {
return nil, err
}
num := len(vals) / 2
result := make(map[string]interface{}, num)
for i := 0; i < num; i++ {
key, _ := redigo.String(vals[2*i], nil)
result[key] = vals[2*i+1]
}
return result, nil
}

// NOTE: Use this in production environment with extreme care.
// Read more here:https://redigo.io/commands/keys
func (p *RedisPool) Keys(pattern string) ([]string, error) {
return redigo.Strings(Do("KEYS", pattern))
}

func (p *RedisPool) HKeys(key string) ([]string, error) {
return redigo.Strings(Do("HKEYS", key))
}

func (p *RedisPool) Exists(key string) (bool, error) {
count, err := redigo.Int(Do("EXISTS", key))
if count == 0 {
return false, err
} else {
return true, err
}
}

func (p *RedisPool) Incr(key string) (int64, error) {
return redigo.Int64(Do("INCR", key))
}

func (p *RedisPool) Decr(key string) (int64, error) {
return redigo.Int64(Do("DECR", key))
}

func (p *RedisPool) IncrBy(key string, incBy int64) (int64, error) {
return redigo.Int64(Do("INCRBY", key, incBy))
}

func (p *RedisPool) DecrBy(key string, decrBy int64) (int64, error) {
return redigo.Int64(Do("DECRBY", key))
}

func (p *RedisPool) IncrByFloat(key string, incBy float64) (float64, error) {
return redigo.Float64(Do("INCRBYFLOAT", key, incBy))
}

func (p *RedisPool) DecrByFloat(key string, decrBy float64) (float64, error) {
return redigo.Float64(Do("DECRBYFLOAT", key, decrBy))
}

// use for message queue
func (p *RedisPool) LPush(key string, data interface{}) (interface{}, error) {
// set
return Do("LPUSH", key, data)
}

func (p *RedisPool) LPop(key string) (interface{}, error) {
return Do("LPOP", key)
}

func (p *RedisPool) LPopString(key string) (string, error) {
return redigo.String(Do("LPOP", key))
}
func (p *RedisPool) LPopFloat(key string) (float64, error) {
f, err := redigo.Float64(Do("LPOP", key))
return float64(f), err
}
func (p *RedisPool) LPopInt(key string) (int, error) {
return redigo.Int(Do("LPOP", key))
}
func (p *RedisPool) LPopInt64(key string) (int64, error) {
return redigo.Int64(Do("LPOP", key))
}

func (p *RedisPool) RPush(key string, data interface{}) (interface{}, error) {
// set
return Do("RPUSH", key, data)
}

func (p *RedisPool) RPop(key string) (interface{}, error) {
return Do("RPOP", key)
}

func (p *RedisPool) RPopString(key string) (string, error) {
return redigo.String(Do("RPOP", key))
}
func (p *RedisPool) RPopFloat(key string) (float64, error) {
f, err := redigo.Float64(Do("RPOP", key))
return float64(f), err
}
func (p *RedisPool) RPopInt(key string) (int, error) {
return redigo.Int(Do("RPOP", key))
}
func (p *RedisPool) RPopInt64(key string) (int64, error) {
return redigo.Int64(Do("RPOP", key))
}

func (p *RedisPool) Scan(cursor int64, pattern string, count int64) (int64, []string, error) {
var items []string
var newCursor int64

values, err := redigo.Values(Do("SCAN", cursor, "MATCH", pattern, "COUNT", count))
if err != nil {
return 0, nil, err
}
values, err = redigo.Scan(values, &newCursor, &items)
if err != nil {
return 0, nil, err
}

return newCursor, items, nil
}

+ 617
- 0
utils/cache/redis_pool_cluster.go View File

@@ -0,0 +1,617 @@
package cache

import (
"strconv"
"time"

"github.com/go-redis/redis"
)

type RedisClusterPool struct {
client *redis.ClusterClient
}

func NewRedisClusterPool(addrs []string) (*RedisClusterPool, error) {
opt := &redis.ClusterOptions{
Addrs: addrs,
PoolSize: 512,
PoolTimeout: 10 * time.Second,
IdleTimeout: 10 * time.Second,
DialTimeout: 10 * time.Second,
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
}
c := redis.NewClusterClient(opt)
if err := c.Ping().Err(); err != nil {
return nil, err
}
return &RedisClusterPool{client: c}, nil
}

func (p *RedisClusterPool) Get(key string) (interface{}, error) {
res, err := p.client.Get(key).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func (p *RedisClusterPool) Set(key string, value interface{}) error {
err := p.client.Set(key, value, 0).Err()
return convertError(err)
}
func (p *RedisClusterPool) GetSet(key string, value interface{}) (interface{}, error) {
res, err := p.client.GetSet(key, value).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func (p *RedisClusterPool) SetNx(key string, value interface{}) (int64, error) {
res, err := p.client.SetNX(key, value, 0).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func (p *RedisClusterPool) SetEx(key string, value interface{}, timeout int64) error {
_, err := p.client.Set(key, value, time.Duration(timeout)*time.Second).Result()
if err != nil {
return convertError(err)
}
return nil
}

// nil表示成功,ErrNil表示数据库内已经存在这个key,其他表示数据库发生错误
func (p *RedisClusterPool) SetNxEx(key string, value interface{}, timeout int64) error {
res, err := p.client.SetNX(key, value, time.Duration(timeout)*time.Second).Result()
if err != nil {
return convertError(err)
}
if res {
return nil
}
return ErrNil
}
func (p *RedisClusterPool) MGet(keys ...string) ([]interface{}, error) {
res, err := p.client.MGet(keys...).Result()
return res, convertError(err)
}

// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test}
func (p *RedisClusterPool) MSet(kvs map[string]interface{}) error {
pairs := make([]string, 0, len(kvs)*2)
for k, v := range kvs {
val, err := String(v, nil)
if err != nil {
return err
}
pairs = append(pairs, k, val)
}
return convertError(p.client.MSet(pairs).Err())
}

// 为确保多个key映射到同一个slot,每个key最好加上hash tag,如:{test}
func (p *RedisClusterPool) MSetNX(kvs map[string]interface{}) (bool, error) {
pairs := make([]string, 0, len(kvs)*2)
for k, v := range kvs {
val, err := String(v, nil)
if err != nil {
return false, err
}
pairs = append(pairs, k, val)
}
res, err := p.client.MSetNX(pairs).Result()
return res, convertError(err)
}
func (p *RedisClusterPool) ExpireAt(key string, timestamp int64) (int64, error) {
res, err := p.client.ExpireAt(key, time.Unix(timestamp, 0)).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func (p *RedisClusterPool) Del(keys ...string) (int64, error) {
args := make([]interface{}, 0, len(keys))
for _, key := range keys {
args = append(args, key)
}
res, err := p.client.Del(keys...).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) Incr(key string) (int64, error) {
res, err := p.client.Incr(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) IncrBy(key string, delta int64) (int64, error) {
res, err := p.client.IncrBy(key, delta).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) Expire(key string, duration int64) (int64, error) {
res, err := p.client.Expire(key, time.Duration(duration)*time.Second).Result()
if err != nil {
return 0, convertError(err)
}
if res {
return 1, nil
}
return 0, nil
}
func (p *RedisClusterPool) Exists(key string) (bool, error) { // todo (bool, error)
res, err := p.client.Exists(key).Result()
if err != nil {
return false, convertError(err)
}
if res > 0 {
return true, nil
}
return false, nil
}
func (p *RedisClusterPool) HGet(key string, field string) (interface{}, error) {
res, err := p.client.HGet(key, field).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func (p *RedisClusterPool) HLen(key string) (int64, error) {
res, err := p.client.HLen(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) HSet(key string, field string, val interface{}) error {
value, err := String(val, nil)
if err != nil && err != ErrNil {
return err
}
_, err = p.client.HSet(key, field, value).Result()
if err != nil {
return convertError(err)
}
return nil
}
func (p *RedisClusterPool) HDel(key string, fields ...string) (int64, error) {
args := make([]interface{}, 0, len(fields)+1)
args = append(args, key)
for _, field := range fields {
args = append(args, field)
}
res, err := p.client.HDel(key, fields...).Result()
if err != nil {
return 0, convertError(err)
}
return res, nil
}

func (p *RedisClusterPool) HMGet(key string, fields ...string) (interface{}, error) {
args := make([]interface{}, 0, len(fields)+1)
args = append(args, key)
for _, field := range fields {
args = append(args, field)
}
if len(fields) == 0 {
return nil, ErrNil
}
res, err := p.client.HMGet(key, fields...).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) HMSet(key string, kvs ...interface{}) error {
if len(kvs) == 0 {
return nil
}
if len(kvs)%2 != 0 {
return ErrWrongArgsNum
}
var err error
v := map[string]interface{}{} // todo change
v["field"], err = String(kvs[0], nil)
if err != nil && err != ErrNil {
return err
}
v["value"], err = String(kvs[1], nil)
if err != nil && err != ErrNil {
return err
}
pairs := make([]string, 0, len(kvs)-2)
if len(kvs) > 2 {
for _, kv := range kvs[2:] {
kvString, err := String(kv, nil)
if err != nil && err != ErrNil {
return err
}
pairs = append(pairs, kvString)
}
}
v["paris"] = pairs
_, err = p.client.HMSet(key, v).Result()
if err != nil {
return convertError(err)
}
return nil
}

func (p *RedisClusterPool) HKeys(key string) ([]string, error) {
res, err := p.client.HKeys(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) HVals(key string) ([]interface{}, error) {
res, err := p.client.HVals(key).Result()
if err != nil {
return nil, convertError(err)
}
rs := make([]interface{}, 0, len(res))
for _, res := range res {
rs = append(rs, res)
}
return rs, nil
}
func (p *RedisClusterPool) HGetAll(key string) (map[string]string, error) {
vals, err := p.client.HGetAll(key).Result()
if err != nil {
return nil, convertError(err)
}
return vals, nil
}
func (p *RedisClusterPool) HIncrBy(key, field string, delta int64) (int64, error) {
res, err := p.client.HIncrBy(key, field, delta).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) ZAdd(key string, kvs ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(kvs)+1)
args = append(args, key)
args = append(args, kvs...)
if len(kvs) == 0 {
return 0, nil
}
if len(kvs)%2 != 0 {
return 0, ErrWrongArgsNum
}
zs := make([]redis.Z, len(kvs)/2)
for i := 0; i < len(kvs); i += 2 {
idx := i / 2
score, err := Float64(kvs[i], nil)
if err != nil && err != ErrNil {
return 0, err
}
zs[idx].Score = score
zs[idx].Member = kvs[i+1]
}
res, err := p.client.ZAdd(key, zs...).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) ZRem(key string, members ...string) (int64, error) {
args := make([]interface{}, 0, len(members))
args = append(args, key)
for _, member := range members {
args = append(args, member)
}
res, err := p.client.ZRem(key, members).Result()
if err != nil {
return res, convertError(err)
}
return res, err
}

func (p *RedisClusterPool) ZRange(key string, min, max int64, withScores bool) (interface{}, error) {
res := make([]interface{}, 0)
if withScores {
zs, err := p.client.ZRangeWithScores(key, min, max).Result()
if err != nil {
return nil, convertError(err)
}
for _, z := range zs {
res = append(res, z.Member, strconv.FormatFloat(z.Score, 'f', -1, 64))
}
} else {
ms, err := p.client.ZRange(key, min, max).Result()
if err != nil {
return nil, convertError(err)
}
for _, m := range ms {
res = append(res, m)
}
}
return res, nil
}
func (p *RedisClusterPool) ZRangeByScoreWithScore(key string, min, max int64) (map[string]int64, error) {
opt := new(redis.ZRangeBy)
opt.Min = strconv.FormatInt(int64(min), 10)
opt.Max = strconv.FormatInt(int64(max), 10)
opt.Count = -1
opt.Offset = 0
vals, err := p.client.ZRangeByScoreWithScores(key, *opt).Result()
if err != nil {
return nil, convertError(err)
}
res := make(map[string]int64, len(vals))
for _, val := range vals {
key, err := String(val.Member, nil)
if err != nil && err != ErrNil {
return nil, err
}
res[key] = int64(val.Score)
}
return res, nil
}
func (p *RedisClusterPool) LRange(key string, start, stop int64) (interface{}, error) {
res, err := p.client.LRange(key, start, stop).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) LSet(key string, index int, value interface{}) error {
err := p.client.LSet(key, int64(index), value).Err()
return convertError(err)
}
func (p *RedisClusterPool) LLen(key string) (int64, error) {
res, err := p.client.LLen(key).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) LRem(key string, count int, value interface{}) (int, error) {
val, _ := value.(string)
res, err := p.client.LRem(key, int64(count), val).Result()
if err != nil {
return int(res), convertError(err)
}
return int(res), nil
}
func (p *RedisClusterPool) TTl(key string) (int64, error) {
duration, err := p.client.TTL(key).Result()
if err != nil {
return int64(duration.Seconds()), convertError(err)
}
return int64(duration.Seconds()), nil
}
func (p *RedisClusterPool) LPop(key string) (interface{}, error) {
res, err := p.client.LPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) RPop(key string) (interface{}, error) {
res, err := p.client.RPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) BLPop(key string, timeout int) (interface{}, error) {
res, err := p.client.BLPop(time.Duration(timeout)*time.Second, key).Result()
if err != nil {
// 兼容redis 2.x
if err == redis.Nil {
return nil, ErrNil
}
return nil, err
}
return res[1], nil
}
func (p *RedisClusterPool) BRPop(key string, timeout int) (interface{}, error) {
res, err := p.client.BRPop(time.Duration(timeout)*time.Second, key).Result()
if err != nil {
// 兼容redis 2.x
if err == redis.Nil {
return nil, ErrNil
}
return nil, convertError(err)
}
return res[1], nil
}
func (p *RedisClusterPool) LPush(key string, value ...interface{}) error {
args := make([]interface{}, 0, len(value)+1)
args = append(args, key)
args = append(args, value...)
vals := make([]string, 0, len(value))
for _, v := range value {
val, err := String(v, nil)
if err != nil && err != ErrNil {
return err
}
vals = append(vals, val)
}
_, err := p.client.LPush(key, vals).Result() // todo ...
if err != nil {
return convertError(err)
}
return nil
}
func (p *RedisClusterPool) RPush(key string, value ...interface{}) error {
args := make([]interface{}, 0, len(value)+1)
args = append(args, key)
args = append(args, value...)
vals := make([]string, 0, len(value))
for _, v := range value {
val, err := String(v, nil)
if err != nil && err != ErrNil {
if err == ErrNil {
continue
}
return err
}
if val == "" {
continue
}
vals = append(vals, val)
}
_, err := p.client.RPush(key, vals).Result() // todo ...
if err != nil {
return convertError(err)
}
return nil
}

// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test}
func (p *RedisClusterPool) BRPopLPush(srcKey string, destKey string, timeout int) (interface{}, error) {
res, err := p.client.BRPopLPush(srcKey, destKey, time.Duration(timeout)*time.Second).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}

// 为确保srcKey跟destKey映射到同一个slot,srcKey和destKey需要加上hash tag,如:{test}
func (p *RedisClusterPool) RPopLPush(srcKey string, destKey string) (interface{}, error) {
res, err := p.client.RPopLPush(srcKey, destKey).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SAdd(key string, members ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(members)+1)
args = append(args, key)
args = append(args, members...)
ms := make([]string, 0, len(members))
for _, member := range members {
m, err := String(member, nil)
if err != nil && err != ErrNil {
return 0, err
}
ms = append(ms, m)
}
res, err := p.client.SAdd(key, ms).Result() // todo ...
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SPop(key string) ([]byte, error) {
res, err := p.client.SPop(key).Result()
if err != nil {
return nil, convertError(err)
}
return []byte(res), nil
}
func (p *RedisClusterPool) SIsMember(key string, member interface{}) (bool, error) {
m, _ := member.(string)
res, err := p.client.SIsMember(key, m).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SRem(key string, members ...interface{}) (int64, error) {
args := make([]interface{}, 0, len(members)+1)
args = append(args, key)
args = append(args, members...)
ms := make([]string, 0, len(members))
for _, member := range members {
m, err := String(member, nil)
if err != nil && err != ErrNil {
return 0, err
}
ms = append(ms, m)
}
res, err := p.client.SRem(key, ms).Result() // todo ...
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SMembers(key string) ([]string, error) {
res, err := p.client.SMembers(key).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) ScriptLoad(luaScript string) (interface{}, error) {
res, err := p.client.ScriptLoad(luaScript).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) EvalSha(sha1 string, numberKeys int, keysArgs ...interface{}) (interface{}, error) {
vals := make([]interface{}, 0, len(keysArgs)+2)
vals = append(vals, sha1, numberKeys)
vals = append(vals, keysArgs...)
keys := make([]string, 0, numberKeys)
args := make([]string, 0, len(keysArgs)-numberKeys)
for i, value := range keysArgs {
val, err := String(value, nil)
if err != nil && err != ErrNil {
return nil, err
}
if i < numberKeys {
keys = append(keys, val)
} else {
args = append(args, val)
}
}
res, err := p.client.EvalSha(sha1, keys, args).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) Eval(luaScript string, numberKeys int, keysArgs ...interface{}) (interface{}, error) {
vals := make([]interface{}, 0, len(keysArgs)+2)
vals = append(vals, luaScript, numberKeys)
vals = append(vals, keysArgs...)
keys := make([]string, 0, numberKeys)
args := make([]string, 0, len(keysArgs)-numberKeys)
for i, value := range keysArgs {
val, err := String(value, nil)
if err != nil && err != ErrNil {
return nil, err
}
if i < numberKeys {
keys = append(keys, val)
} else {
args = append(args, val)
}
}
res, err := p.client.Eval(luaScript, keys, args).Result()
if err != nil {
return nil, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) GetBit(key string, offset int64) (int64, error) {
res, err := p.client.GetBit(key, offset).Result()
if err != nil {
return res, convertError(err)
}
return res, nil
}
func (p *RedisClusterPool) SetBit(key string, offset uint32, value int) (int, error) {
res, err := p.client.SetBit(key, int64(offset), value).Result()
return int(res), convertError(err)
}
func (p *RedisClusterPool) GetClient() *redis.ClusterClient {
return pools
}

+ 3
- 0
utils/convert.go View File

@@ -280,6 +280,9 @@ func Float64ToStrPrec1(f float64) string {
func Float64ToStrPrec4(f float64) string {
return strconv.FormatFloat(f, 'f', 4, 64)
}
func Float64ToStrPrec10(f float64) string {
return strconv.FormatFloat(f, 'f', 10, 64)
}

func Float64ToStrPrec6(f float64) string {
return strconv.FormatFloat(f, 'f', 6, 64)


+ 29
- 0
utils/time2s.go View File

@@ -0,0 +1,29 @@
package zhios_order_relate_utils

import "time"

func Time2String(date time.Time, format string) string {
if format == "" {
format = "2006-01-02 15:04:05"
}
timeS := date.Format(format)
if timeS == "0001-01-01 00:00:00" {
return ""
}
return timeS
}
func String2Time(timeStr string) time.Time {
toTime, err := time.ParseInLocation("2006-01-02 15:04:05", timeStr, time.Local)
if err != nil {
return time.Now()
}
return toTime
}

//GetDiffDays 获取两个时间相差的天数,0表同一天,正数表t1>t2,负数表t1<t2
func GetDiffDays(t1, t2 time.Time) int {
t1 = time.Date(t1.Year(), t1.Month(), t1.Day(), 0, 0, 0, 0, time.Local)
t2 = time.Date(t2.Year(), t2.Month(), t2.Day(), 0, 0, 0, 0, time.Local)

return int(t1.Sub(t2).Hours() / 24)
}

Loading…
Cancel
Save