Commit 7aca0b0f authored by hujiebin's avatar hujiebin

init

parents
Pipeline #1900 failed with stages
MODE=local
.idea
/protocol/userProxy/
/protocol/userCenter/
/protocol/biz/
proto:
protoc --go_out=./ --go-grpc_out=. ./protocol/*.proto
\ No newline at end of file
package algo
import (
"context"
"encoding/json"
"fmt"
"github.com/go-redis/redis/v8"
"github.com/golang/protobuf/proto"
uuid "github.com/satori/go.uuid"
"hilo-algoCenter/common"
"hilo-algoCenter/common/config"
"hilo-algoCenter/common/mylogrus"
"hilo-algoCenter/cv"
"hilo-algoCenter/protocol"
"hilo-algoCenter/protocol/userCenter"
"hilo-algoCenter/protocol/userProxy"
"math/rand"
"sort"
"strconv"
"strings"
"time"
)
/*const (
match_wait_duration = 10
)*/
//结果
type MatchResult struct {
//channelId string
User1Id uint64
user1External string
//user1Token string
User2Id uint64
user2External string
//user2Token string
Priority float64
//user2Id的质量分数
Excellen float64
//user1Id同user2Id的关系分数
Relation float64
ExcellentRelation float64
}
func matchSuccess(c userCenter.UserClient, uids []uint64, msgType uint32, data []byte) error {
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
rsp, err := c.Multicast(ctx, &userCenter.MulticastMessage{
Uids: uids,
MsgType: msgType,
PayLoad: data,
})
if err != nil && rsp == nil {
mylogrus.MyLog.Errorf("Multicast message failed %s", err.Error())
}
if rsp != nil && len(rsp.FailedUids) > 0 {
err = fmt.Errorf("%d users failed", len(rsp.FailedUids))
}
return err
}
func Start(userClient userCenter.UserClient, rdb *redis.Client) {
// 秒执行一次
ticker := time.NewTicker(time.Second * 1)
go func() {
for range ticker.C {
go func() {
joinNum, matchResults, matchFails, tradeUnionMap, cycleStr, flag := start()
if flag {
//匹配成功的
for i := 0; i < len(matchResults); i++ {
go processMatchSuccess(userClient, matchResults[i], cycleStr, rdb)
}
//落单的
for i := 0; i < len(matchFails); i++ {
go processMatchFail(userClient, matchFails[i], cycleStr, rdb)
}
//一次匹配中,没有匹配结果,落单的人中,过滤了工会用户,只剩下一个人,
var tradeUnionBroadcast uint8 = 2
if len(matchResults) == 0 && len(matchFails) > 0 {
mylogrus.MyLog.Infof("match cycle %v, check tradeUnionBroadcast", cycleStr)
var n = 0
for i := 0; i < len(matchFails); i++ {
if _, ok := tradeUnionMap[strconv.Itoa(int(matchFails[i].User1Id))]; !ok {
n++
mylogrus.MyLog.Infof("match cycle %v, check tradeUnionBroadcast add n, n:%v", cycleStr, n)
}
}
mylogrus.MyLog.Infof("match cycle %v, check tradeUnionBroadcast result, n:%v", cycleStr, n)
if n == 1 {
//redis广播
tradeUnionBroadcast = 1
}
}
go publishMatchCycle(rdb, protocol.MatchCycle{
MatchCycle: cycleStr,
JoinNum: uint32(joinNum),
SuccessNum: uint32(len(matchResults) * 2),
FailNum: uint32(len(matchFails)),
TradeUnionBroadcast: tradeUnionBroadcast,
})
}
}()
}
}()
}
func publishMatchResult(rdb *redis.Client, result protocol.MatchResult) {
buf, err := json.Marshal(result)
if err != nil {
mylogrus.MyLog.Errorf("publishMatchResult json fail:%s", err.Error())
} else {
val, err := rdb.Publish(context.Background(), protocol.MatchResultPubSubChannel, string(buf)).Result()
if err != nil {
mylogrus.MyLog.Errorf("Publish match failed,val:%v, err: %s", val, err.Error())
} else {
mylogrus.MyLog.Infof("Publish match succeeded, val = %d", val)
}
}
}
func publishMatchCycle(rdb *redis.Client, result protocol.MatchCycle) {
buf, err := json.Marshal(result)
if err != nil {
mylogrus.MyLog.Errorf("json fail:%v", err)
} else {
val, err := rdb.Publish(context.Background(), protocol.MatchCyclePubSubChannel, string(buf)).Result()
if err != nil {
mylogrus.MyLog.Errorf("Publish cycle failed,val:%v, err: %s", val, err.Error())
} else {
mylogrus.MyLog.Infof("Publish cycle succeeded, val = %d", val)
}
}
}
//用户同分数
type UserAndScore struct {
userId string
score float64
excellen float64
relation float64
sex string
isVip bool
country string
externalId string
}
type UserPriority struct {
userId string
score float64
sex string
country string
externalId string
isVip bool
}
//开始
func start() (int, []MatchResult, []MatchResult, map[string]bool, string, bool) {
cycle := (time.Now().Unix() - int64(config.GetMatchConfig().MATCH_CYCLE)) / int64(config.GetMatchConfig().MATCH_CYCLE)
cycleStr := strconv.Itoa(int(cycle))
flag, err := SetCycle(cycle)
if err != nil {
mylogrus.MyLog.Errorf("match cycle %v start setNx err: %v", cycleStr, err)
}
if flag {
mylogrus.MyLog.Infof("match cycle %v start match ", cycleStr)
joinNum, matchResult, matchFails, tradeUnionMap := cal(cycle)
return joinNum, matchResult, matchFails, tradeUnionMap, cycleStr, true
}
mylogrus.MyLog.Infof("match cycle %v start has exist", cycleStr)
return 0, []MatchResult{}, []MatchResult{}, map[string]bool{}, cycleStr, false
}
//计算分数
func cal(cycle int64) (int, []MatchResult, []MatchResult, map[string]bool) {
matchCycle := InitMatchCycle(cycle)
//匹配的结果
var matchResults []MatchResult
//已经被匹配的用户
hasMatch := map[string]bool{}
//没有匹配到的用户
var noMatch []UserPriority
//无序的工会用户
//tradeUnions, tradeUnionMap := initTradeUnion(matchCycle)
_, tradeUnionMap := initTradeUnion(matchCycle)
//推荐用户
manRecommend, womanRecommend := initRecommend(matchCycle)
//Priority是升序排序
userAndScore, userPrioritys, err := initUserAndScore(matchCycle)
priorityNum := len(userPrioritys)
if err != nil {
mylogrus.MyLog.Errorln("match cycle:%v, init userInfo and excellent score err:", matchCycle.GetCycle(), err)
}
//从高到低排序
sort.Slice(userAndScore, func(i, j int) bool {
return userAndScore[i].score > userAndScore[j].score
})
mylogrus.MyLog.Infof("match cycle:%v, init userInfo and excellent score success, start match", matchCycle.GetCycle())
//开始循环优先级分数
for i := len(userPrioritys) - 1; i >= 0; i-- {
if _, ok := hasMatch[userPrioritys[i].userId]; ok {
mylogrus.MyLog.Infof("match cycle:%v, priority userId: %v has bean matched", matchCycle.GetCycle(), userPrioritys[i].userId)
continue
}
mylogrus.MyLog.Infof("match cycle:%v, priority userId: %v,score:%v finding user", matchCycle.GetCycle(), userPrioritys[i].userId, userPrioritys[i].score)
//
newUserAndScore := copyUserAndScore(userAndScore, userPrioritys)
mylogrus.MyLog.Infof("match cycle:%v, priority userId: %v,copy init data", matchCycle.GetCycle(), userPrioritys[i].userId)
addRelationScore(matchCycle, userPrioritys[i].userId, newUserAndScore)
mylogrus.MyLog.Infof("match cycle:%v, priority userId: %v,cal relation score success", matchCycle.GetCycle(), userPrioritys[i].userId)
//进行排序
sort.Slice(newUserAndScore, func(i, j int) bool {
return newUserAndScore[i].score > newUserAndScore[j].score
})
//
var m *MatchResult = nil
for j := 0; j < len(newUserAndScore); j++ {
flag := matchUser(matchCycle, hasMatch, tradeUnionMap, userPrioritys[i], newUserAndScore[j])
if flag {
m = initResult(userPrioritys[i].userId, userPrioritys[i].externalId, newUserAndScore[j].userId, newUserAndScore[j].externalId, userPrioritys[i].score, newUserAndScore[j].excellen, newUserAndScore[j].relation, newUserAndScore[j].score)
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,match success", matchCycle.GetCycle(), m.User1Id, m.User2Id)
break
} else {
continue
}
}
if m == nil {
//user164, _ := strconv.ParseUint(userPrioritys[i].userId, 10, 64)
noMatch = append(noMatch, userPrioritys[i])
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v match fail alone", matchCycle.GetCycle(), userPrioritys[i].userId)
} else {
//
hasMatch[strconv.Itoa(int(m.User1Id))] = true
hasMatch[strconv.Itoa(int(m.User2Id))] = true
matchResults = append(matchResults, *m)
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,match success to record", matchCycle.GetCycle(), m.User1Id, m.User2Id)
}
//移除
userPrioritys = append(userPrioritys[0:i])
}
mylogrus.MyLog.Infof("match cycle:%v, relation match end,join user num:%v succes num:%v,single num:%v", matchCycle.GetCycle(), priorityNum, len(matchResults), len(noMatch))
//落单的匹配
singleResults := toSingleMatch(matchCycle, hasMatch, tradeUnionMap, noMatch, manRecommend, womanRecommend)
mylogrus.MyLog.Infof("match cycle:%v, all end,join user num:%v succes num:%v,single num:%v", matchCycle.GetCycle(), priorityNum, len(matchResults), len(singleResults))
return priorityNum, matchResults, singleResults, tradeUnionMap
}
func initResult(user1Id string, user1External string, user2Id string, user2External string, priority float64, excellen float64, relation float64, excellentRelation float64) *MatchResult {
user164, _ := strconv.ParseUint(user1Id, 10, 64)
user264, _ := strconv.ParseUint(user2Id, 10, 64)
return &MatchResult{
User1Id: user164,
user1External: user1External,
User2Id: user264,
user2External: user2External,
Priority: priority,
Excellen: excellen,
Relation: relation,
ExcellentRelation: excellentRelation,
}
}
/**
* @Description 初始化,推荐信息
* @return 男性用户信息, 女性用户信息
**/
func initRecommend(matchCycle *MatchCycle) ([]UserAndScore, []UserAndScore) {
recommendCaches, err := GetRecommendCache()
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, initRecommend fail,err:%v", matchCycle.GetCycle(), err)
return []UserAndScore{}, []UserAndScore{}
}
var manUserAndScore []UserAndScore
var womanUserAndScore []UserAndScore
r := rand.New(rand.NewSource(time.Now().Unix()))
perm := r.Perm(len(recommendCaches))
for _, randIndex := range perm {
userAndScore := UserAndScore{
userId: strconv.Itoa(int(recommendCaches[randIndex].UserId)),
sex: strconv.Itoa(int(recommendCaches[randIndex].Sex)),
country: recommendCaches[randIndex].Country,
externalId: recommendCaches[randIndex].ExternalId,
}
if recommendCaches[randIndex].Sex == 1 {
//男性
manUserAndScore = append(manUserAndScore, userAndScore)
} else {
//女性
womanUserAndScore = append(womanUserAndScore, userAndScore)
}
}
return manUserAndScore, womanUserAndScore
}
/**
* @Description 初始化,工会用户
* @return map[string]bool。是为了防止两个工会用户匹配上
**/
func initTradeUnion(matchCycle *MatchCycle) ([]UserAndScore, map[string]bool) {
matchTradeUnionCaches, err := GetMatchTradeUnionCache(matchCycle.GetCycle())
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, initTradeUnion fail,err:%v", matchCycle.GetCycle(), err)
return []UserAndScore{}, map[string]bool{}
} else {
mylogrus.MyLog.Infof("match cycle:%v, initTradeUnion success, tradeUnionNum:%v", matchCycle.GetCycle(), len(matchTradeUnionCaches))
}
userAndScores := make([]UserAndScore, len(matchTradeUnionCaches))
userMap := map[string]bool{}
r := rand.New(rand.NewSource(time.Now().Unix()))
perm := r.Perm(len(matchTradeUnionCaches))
for i, randIndex := range perm {
userAndScores[i] = UserAndScore{
userId: strconv.Itoa(int(matchTradeUnionCaches[randIndex].UserId)),
sex: strconv.Itoa(int(matchTradeUnionCaches[randIndex].Sex)),
country: matchTradeUnionCaches[randIndex].Country,
externalId: matchTradeUnionCaches[randIndex].ExternalId,
}
userMap[strconv.Itoa(int(matchTradeUnionCaches[randIndex].UserId))] = true
}
mylogrus.MyLog.Infof("match cycle:%v, initTradeUnion success, num:%v", matchCycle.GetCycle(), len(userAndScores))
return userAndScores, userMap
}
//初始化,用户同分数,
func initUserAndScore(matchCycle *MatchCycle) ([]UserAndScore, []UserPriority, error) {
mylogrus.MyLog.Infof("match cycle:%v, initUserAndScore userinfo, excellent score", matchCycle.GetCycle())
//优先级排队的人
zList, err := getPriorityData(matchCycle)
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, initUserAndScore getPriorityData fail,err:%v", matchCycle.GetCycle(), err)
return nil, nil, err
}
mylogrus.MyLog.Infof("match cycle:%v, initUserAndScore getPriorityData success,join num:%v", matchCycle.GetCycle(), len(zList))
mylogrus.MyLog.Infof("match cycle:%v, initUserAndScore print join user:%v", matchCycle.GetCycle(), zList)
if len(zList) == 0 {
return []UserAndScore{}, []UserPriority{}, nil
}
//优先级
var uPrioritys []UserPriority
//分数
var uList []UserAndScore
//用户Ids
var userIds []string
for i := 0; i < len(zList); i++ {
userId := zList[i].Member.(string)
uPrioritys = append(uPrioritys, UserPriority{
userId: userId,
score: zList[i].Score,
})
uList = append(uList, UserAndScore{
userId: userId,
})
userIds = append(userIds, userId)
}
//构建用户性别同国籍
addSexAndCountryVip(matchCycle, uList, uPrioritys, userIds)
mylogrus.MyLog.Infof("match cycle:%v, initUserAndScore add sex,country", matchCycle.GetCycle())
//构建质量分数
addExcellentScore(matchCycle, uList)
mylogrus.MyLog.Infof("match cycle:%v, initUserAndScore addExcellentScore ", matchCycle.GetCycle())
return uList, uPrioritys, nil
}
//增加性别
func addSexAndCountryVip(matchCycle *MatchCycle, uList []UserAndScore, uPrioritys []UserPriority, userIds []string) {
userCacheMap, err := matchCycle.GetUser(userIds)
if err != nil {
//打印错误,不处理错误,核心业务,接受容错
mylogrus.MyLog.Errorf("match cycle:%v, addSexAndCountry, err:%v", matchCycle.GetCycle(), err)
}
for i := 0; i < len(uList); i++ {
userCache, ok := userCacheMap[uList[i].userId]
if ok {
uList[i].sex = strconv.Itoa(int(userCache.Sex))
uList[i].country = userCache.Country
uList[i].externalId = userCache.ExternalId
uList[i].isVip = userCache.IsVip
mylogrus.MyLog.Infof("match cycle:%v, addSexAndCountry success,userId:%v, sex:%v, country:%v, isVip:%v", matchCycle.GetCycle(), uList[i].userId, uList[i].sex, uList[i].country, uList[i].isVip)
}
}
for i := 0; i < len(uPrioritys); i++ {
userCache, ok := userCacheMap[uPrioritys[i].userId]
if ok {
uPrioritys[i].sex = strconv.Itoa(int(userCache.Sex))
uPrioritys[i].country = userCache.Country
uPrioritys[i].externalId = userCache.ExternalId
uPrioritys[i].isVip = userCache.IsVip
mylogrus.MyLog.Infof("match cycle:%v, addSexAndCountry detail,userId:%v, sex:%v, country:%v, isVip:%v", matchCycle.GetCycle(), uPrioritys[i].userId, uPrioritys[i].sex, uPrioritys[i].country, userCache.IsVip)
}
}
}
//构建质量分数
func addExcellentScore(matchCycle *MatchCycle, uList []UserAndScore) {
zList, err := matchCycle.GetExcellentData()
if err != nil {
//打印错误,不处理错误,核心业务,接受容错
mylogrus.MyLog.Errorf("match cycle:%v, addExcellentScore, err:%v", matchCycle.GetCycle(), err)
}
mylogrus.MyLog.Infof("match cycle:%v, addExcellentScore success userNum:%v, joinNum:%v", matchCycle.GetCycle(), len(zList), len(uList))
excellentScoreMap := map[string]float64{}
for _, v := range zList {
excellentScoreMap[v.Member.(string)] = v.Score
}
//
for i := 0; i < len(uList); i++ {
f, ok := excellentScoreMap[uList[i].userId]
if ok {
uList[i].excellen = f
uList[i].score = f
mylogrus.MyLog.Infof("match cycle:%v, addExcellentScore detail,userId:%v, score:%v", matchCycle.GetCycle(), uList[i].userId, uList[i].score)
}
}
}
//计算,质量分数 + 关系分数
func addRelationScore(matchCycle *MatchCycle, userId string, u []UserAndScore) {
if len(u) == 0 {
return
}
relationScoreMap, err := getRelationData(matchCycle, userId)
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, addRelationScore err:%v", matchCycle.GetCycle(), err)
return
}
for i := 0; i < len(u); i++ {
f, ok := relationScoreMap[u[i].userId]
if ok {
u[i].relation = f
u[i].score = u[i].score + f
mylogrus.MyLog.Infof("match cycle:%v, addRelationScore detail userId: %v, relation otherUserId:%v,score:%v", matchCycle.GetCycle(), userId, u[i].userId, f)
}
}
}
//落单,没有匹配成功的
func processMatchFail(userClient userCenter.UserClient, val MatchResult, matchCycle string, rdb *redis.Client) {
user2Info, _ := cv.GetOtherUserInfo(val.User1Id, val.User2Id)
msg := &userProxy.MatchSuccess{
LocalUserId: val.user1External,
RemoteUserId: val.user2External,
WaitDuration: config.GetMatchConfig().MATCH_SUCCESS_WAIT_DURATION,
MatchUniqueId: strings.Replace(uuid.NewV4().String(), "-", "", -1),
Status: false,
SingleWaitTimeInSec: config.GetMatchConfig().MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC,
DualWaitTimeInSec: config.GetMatchConfig().MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC,
RemoteUser: user2Info,
}
if buffer, err := proto.Marshal(msg); err == nil {
rPcErr := ""
matchSuccess(userClient, []uint64{val.User1Id}, common.MsgTypeMatchSuccess, buffer) // todo for updating
if err = matchSuccess(userClient, []uint64{val.User1Id}, common.MsgTypeMatchV2Success, buffer); err == nil {
mylogrus.MyLog.Infof("match cycle:%v, match result sent msg success, single LocalUserId:%v, RemoteUserId %v\n", matchCycle, msg.LocalUserId, msg.RemoteUserId)
} else {
mylogrus.MyLog.Errorf("match cycle:%v, match result sent msg fail, single LocalUserId:%v, RemoteUserId %v\n", matchCycle, msg.LocalUserId, msg.RemoteUserId)
rPcErr = err.Error()
}
go publishMatchResult(rdb, protocol.MatchResult{
MatchCycle: matchCycle,
MatchUniqueId: msg.MatchUniqueId,
User1Id: val.User1Id,
User2Id: val.User2Id,
Status: false,
Priority: val.Priority,
Excellen: val.Excellen,
Relation: val.Relation,
ExcellentRelation: val.ExcellentRelation,
RpcStatus: err == nil,
RPcErr: rPcErr,
})
}
}
//发布匹配成功
func processMatchSuccess(userClient userCenter.UserClient, val MatchResult, matchCycle string, rdb *redis.Client) {
mylogrus.MyLog.Infof("Processing %v\n", val)
uids := []uint64{val.User1Id}
user1Info, _ := cv.GetOtherUserInfo(val.User2Id, val.User1Id)
user2Info, _ := cv.GetOtherUserInfo(val.User1Id, val.User2Id)
msg := &userProxy.MatchSuccess{
LocalUserId: val.user1External,
RemoteUserId: val.user2External,
WaitDuration: config.GetMatchConfig().MATCH_SUCCESS_WAIT_DURATION,
MatchUniqueId: strings.Replace(uuid.NewV4().String(), "-", "", -1),
Status: true,
SingleWaitTimeInSec: config.GetMatchConfig().MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC,
DualWaitTimeInSec: config.GetMatchConfig().MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC,
RemoteUser: user2Info,
}
ok1 := false
ok2 := false
if buffer, err := proto.Marshal(msg); err == nil {
matchSuccess(userClient, uids, common.MsgTypeMatchSuccess, buffer) // todo for updating
if err = matchSuccess(userClient, uids, common.MsgTypeMatchV2Success, buffer); err == nil {
mylogrus.MyLog.Infof("match cycle:%v, match result sent msg begin LocalUserId:%v, RemoteUserId:%v, LocalUserId:%v, RemoteUserId:%v\n", matchCycle, msg.LocalUserId, msg.RemoteUserId, val.User1Id, val.User2Id)
ok1 = true
// 交换数据
uids[0] = val.User2Id
msg.LocalUserId = val.user2External
msg.RemoteUserId = val.user1External
msg.RemoteUser = user1Info
if buffer, err = proto.Marshal(msg); err == nil {
matchSuccess(userClient, uids, common.MsgTypeMatchSuccess, buffer) // todo for updating
if err = matchSuccess(userClient, uids, common.MsgTypeMatchV2Success, buffer); err == nil {
ok2 = true
mylogrus.MyLog.Infof("match cycle:%v, match result sent msg success LocalUserId:%v, RemoteUserId:%v, LocalUserId:%v, RemoteUserId:%v\n", matchCycle, msg.LocalUserId, msg.RemoteUserId, val.User1Id, val.User2Id)
}
}
}
rpcErr := ""
if err != nil {
rpcErr = err.Error()
}
//redis广播
go publishMatchResult(rdb, protocol.MatchResult{
MatchCycle: matchCycle,
MatchUniqueId: msg.MatchUniqueId,
User1Id: val.User1Id,
User2Id: val.User2Id,
Status: true,
Priority: val.Priority,
Excellen: val.Excellen,
Relation: val.Relation,
ExcellentRelation: val.ExcellentRelation,
RpcStatus: ok1 && ok2,
RPcErr: rpcErr,
})
if !ok1 {
mylogrus.MyLog.Errorf("match cycle:%v, match result sent msg fail user", val.User1Id)
}
if !ok2 {
mylogrus.MyLog.Errorf("match cycle:%v, match result sent msg fail user", val.User2Id)
}
}
}
//获取匹配优先级
func getPriorityData(matchCycle *MatchCycle) ([]redis.Z, error) {
zList, err := matchCycle.GetPriorityData()
if err != nil {
return nil, err
}
return zList, nil
}
//获取关系分数
func getRelationData(matchCycle *MatchCycle, userId string) (map[string]float64, error) {
relations, err := matchCycle.GetRelationData(userId)
if err != nil {
return map[string]float64{}, err
}
m := map[string]float64{}
for _, v := range relations {
m[strconv.Itoa(int(v.RelationUserId))] = v.Score
}
return m, nil
}
//复制内容
func copyUserAndScore(list []UserAndScore, userPrioritys []UserPriority) []UserAndScore {
userIdMap := map[string]bool{}
for i := 0; i < len(userPrioritys); i++ {
userIdMap[userPrioritys[i].userId] = true
}
var u []UserAndScore
for i := 0; i < len(list); i++ {
if _, ok := userIdMap[list[i].userId]; ok {
u = append(u, list[i])
}
}
return u
}
//检查要匹配的用户
func matchUser(matchCycle *MatchCycle, hasMatch map[string]bool, tradeUnionMap map[string]bool, user UserPriority, otherUser UserAndScore) bool {
if user.userId == otherUser.userId {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v myself,skip", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
//是否存在已匹配中
if _, ok := hasMatch[otherUser.userId]; ok {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v has been match", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
//是否均为工会用户
_, ok1 := tradeUnionMap[user.userId]
_, ok2 := tradeUnionMap[otherUser.userId]
if ok1 && ok2 {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v both in tradeUnion", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
//判断是否存在拉黑
flag, err := matchCycle.CheckBlock(user.userId, otherUser.userId)
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, relation userId: %v,otherUserId:%v, check black ,err:%v", matchCycle.GetCycle(), user.userId, otherUser.userId, err)
return false
}
//存在拉黑
if flag {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v, has black, skip", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
//存在条件搜索
sex1, err := matchCycle.GetConditionSex(user.userId)
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, relation userId: %v,get match condition sex ,err:%v", matchCycle.GetCycle(), user.userId, err)
return false
}
country1, err := matchCycle.GetConditionCountry(user.userId)
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, relation userId: %v,get match condition country,err:%v", matchCycle.GetCycle(), user.userId, err)
return false
}
//另一个人的条件刷选
sex2, err := matchCycle.GetConditionSex(otherUser.userId)
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, relation userId: %v,get match condition sex,err:%v", matchCycle.GetCycle(), otherUser.userId, err)
return false
}
country2, err := matchCycle.GetConditionCountry(otherUser.userId)
if err != nil {
mylogrus.MyLog.Errorf("match cycle:%v, relation userId: %v,get match condition country,err:%v", matchCycle.GetCycle(), otherUser.userId, err)
return false
}
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v, tradeUnion:%v, isVip:%v, condition(sex:%v, country:%v) myself(:sex:%v, country:%v )"+
",otherUserId:%v ,tradeUnion:%v, isVip:%v,condition(sex:%v, country:%v) otherUserSelf(:sex:%v, country:%v)", matchCycle.GetCycle(), user.userId, tradeUnionMap[user.userId], user.isVip, sex1, country1, user.sex, user.country, otherUser.userId, tradeUnionMap[otherUser.userId], otherUser.isVip, sex2, country2, otherUser.sex, otherUser.country)
//需求,2022/03/07 需求增加公会用户只能与VIP用户进行匹配
/* if flag := tradeUnionMap[user.userId]; flag {
//公会用户, 匹配上是非vip
if !otherUser.isVip {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,condition tradeUnion not vip", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
}
if flag := tradeUnionMap[otherUser.userId]; flag {
//公会用户, 匹配上是非vip
if !user.isVip {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,condition tradeUnion not vip", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
}*/
if sex1 == "" && country1 == "" && sex2 == "" && country2 == "" {
//
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,all not conditon, match success", matchCycle.GetCycle(), user.userId, otherUser.userId)
//m = initResult(user.userId, user.externalId, otherUser.userId, otherUser.externalId)
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,match success", matchCycle.GetCycle(), user.userId, otherUser.userId)
return true
}
if sex1 != "" && sex1 != otherUser.sex {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,condition sex not match", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
if sex2 != "" && sex2 != user.sex {
mylogrus.MyLog.Infof("match cycle:%v, relation 用户userId: %v,otherUserId:%v,condition sex not match", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
if country1 != "" && country1 != otherUser.country {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,condition country not match", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
if country2 != "" && country2 != user.country {
mylogrus.MyLog.Infof("match cycle:%v, relation userId: %v,otherUserId:%v,condition country not match", matchCycle.GetCycle(), user.userId, otherUser.userId)
return false
}
return true
}
//func toSingleMatch(matchCycle *myredis.MatchCycle, hasMatch map[string]bool, tradeUnionMap map[string]bool, noMatch []UserPriority, tradeUnions []UserAndScore) []MatchResult {
func toSingleMatch(matchCycle *MatchCycle, hasMatch map[string]bool, tradeUnionMap map[string]bool, noMatch []UserPriority, manRecommon []UserAndScore, womanRecommon []UserAndScore) []MatchResult {
var singleResults []MatchResult
for i := 0; i < len(noMatch); i++ {
var singleM *MatchResult = nil
//如果是公会用户,不能匹配离线用户
_, ok := tradeUnionMap[noMatch[i].userId]
if !ok {
//不断的遍历。利用hasMath来控制,重复匹配的
//如果是男性, 有限匹配女性
if noMatch[i].sex == "1" {
for j := 0; j < len(womanRecommon); j++ {
flag := matchUser(matchCycle, hasMatch, tradeUnionMap, noMatch[i], womanRecommon[j])
if flag {
singleM = initResult(noMatch[i].userId, noMatch[i].externalId, womanRecommon[j].userId, womanRecommon[j].externalId, noMatch[i].score, 0, 0, 0)
//找到了就退出
break
} else {
continue
}
}
//找不到
if singleM == nil {
for j := 0; j < len(manRecommon); j++ {
flag := matchUser(matchCycle, hasMatch, tradeUnionMap, noMatch[i], manRecommon[j])
if flag {
singleM = initResult(noMatch[i].userId, noMatch[i].externalId, manRecommon[j].userId, manRecommon[j].externalId, noMatch[i].score, 0, 0, 0)
//找到了就退出
break
} else {
continue
}
}
}
} else {
for j := 0; j < len(manRecommon); j++ {
flag := matchUser(matchCycle, hasMatch, tradeUnionMap, noMatch[i], manRecommon[j])
if flag {
singleM = initResult(noMatch[i].userId, noMatch[i].externalId, manRecommon[j].userId, manRecommon[j].externalId, noMatch[i].score, 0, 0, 0)
//找到了就退出
break
} else {
continue
}
}
if singleM == nil {
for j := 0; j < len(womanRecommon); j++ {
flag := matchUser(matchCycle, hasMatch, tradeUnionMap, noMatch[i], womanRecommon[j])
if flag {
singleM = initResult(noMatch[i].userId, noMatch[i].externalId, womanRecommon[j].userId, womanRecommon[j].externalId, noMatch[i].score, 0, 0, 0)
//找到了就退出
break
} else {
continue
}
}
}
}
}
/* for j := 0; j < len(tradeUnions); j++ {
flag := matchUser(matchCycle, hasMatch, tradeUnionMap, noMatch[i], tradeUnions[j])
if flag {
singleM = initResult(noMatch[i].userId, noMatch[i].externalId, tradeUnions[j].userId, tradeUnions[j].externalId, noMatch[i].score, 0, 0, 0)
} else {
continue
}
}*/
if singleM != nil {
hasMatch[strconv.Itoa(int(singleM.User1Id))] = true
hasMatch[strconv.Itoa(int(singleM.User2Id))] = true
singleResults = append(singleResults, *singleM)
mylogrus.MyLog.Infof("match cycle:%v, single userId: %v,otherUserId:%v,match success to record", matchCycle.GetCycle(), singleM.User1Id, singleM.User2Id)
} else {
user164, _ := strconv.ParseUint(noMatch[i].userId, 10, 64)
singleM = &MatchResult{
User1Id: user164,
user1External: noMatch[i].externalId,
Priority: noMatch[i].score,
}
hasMatch[strconv.Itoa(int(singleM.User1Id))] = true
singleResults = append(singleResults, *singleM)
mylogrus.MyLog.Infof("match cycle:%v, singel userId: %v match fail alone", matchCycle.GetCycle(), singleM.User1Id)
}
}
return singleResults
}
package algo
import (
"context"
"encoding/json"
"github.com/go-redis/redis/v8"
"hilo-algoCenter/common/config"
"hilo-algoCenter/common/mylogrus"
"hilo-algoCenter/common/redisCli"
"strconv"
"strings"
"time"
)
type RecommendUserCache struct {
UserId uint64
Sex uint8
Country string
ExternalId string
}
// MatchCycle 匹配周期
type MatchCycle struct {
cycle string
}
type MatchTradeUnionCache struct {
UserId uint64
Sex uint8
Country string
ExternalId string
}
// MatchUserCache 用户信息
type MatchUserCache struct {
UserId uint64
Sex uint8
Country string
ExternalId string
IsVip bool
}
// MatchRelation 用户关系分数
type MatchRelation struct {
UserId uint64
RelationUserId uint64
Score float64
}
func GetMatchCycle() int64 {
return time.Now().Unix() / int64(config.GetMatchConfig().MATCH_CYCLE)
}
func SetCycle(cycle int64) (bool, error) {
return redisCli.RedisClient.SetNX(context.Background(), GetPrefixMatchCycle(cycle), cycle, time.Hour).Result()
}
// InitMatchCycle 初始化匹配周期
func InitMatchCycle(cycle int64) *MatchCycle {
return &MatchCycle{cycle: strconv.Itoa(int(cycle))}
}
func (matchCycle *MatchCycle) GetCycle() string {
return matchCycle.cycle
}
func (matchCycle *MatchCycle) GetUser(userIds []string) (map[string]MatchUserCache, error) {
key := GetPrefixMatchUser(matchCycle.cycle)
dList, err := redisCli.RedisClient.HMGet(context.Background(), key, userIds...).Result()
if err != nil {
return nil, err
}
userCacheMap := map[string]MatchUserCache{}
for _, v := range dList {
//转换成json
matchUserCache := MatchUserCache{}
if err := json.Unmarshal([]byte(v.(string)), &matchUserCache); err != nil {
mylogrus.MyLog.Errorf("match cache user 转换成结构失败,string:%v, 错误:%v", v.(string), err)
}
userCacheMap[strconv.Itoa(int(matchUserCache.UserId))] = matchUserCache
}
return userCacheMap, nil
}
// GetExcellentData 获取某个周期下,获取所有的质量分数
func (matchCycle *MatchCycle) GetExcellentData() ([]redis.Z, error) {
key := GetPrefixMatchExcellent(matchCycle.cycle)
zList, err := redisCli.RedisClient.ZRangeWithScores(context.Background(), key, 0, -1).Result()
if err != nil {
return nil, err
}
return zList, nil
}
// GetPriorityData 获取某个周期下,获取的排序数据
func (matchCycle *MatchCycle) GetPriorityData() ([]redis.Z, error) {
key := GetPrefixMatchPriority(matchCycle.cycle)
zList, err := redisCli.RedisClient.ZRangeWithScores(context.Background(), key, 0, -1).Result()
if err != nil {
return nil, err
}
return zList, nil
}
// GetRelationData 获取关系分数
func (matchCycle *MatchCycle) GetRelationData(userId string) ([]MatchRelation, error) {
key := GetPrefixMatchRelation(matchCycle.cycle, userId)
values, err := redisCli.RedisClient.HVals(context.Background(), key).Result()
if err != nil {
return nil, err
}
var matchRelations []MatchRelation
for _, v := range values {
var matchRelation MatchRelation
if err := json.Unmarshal([]byte(v), &matchRelation); err != nil {
mylogrus.MyLog.Errorf("match cache matchRelations 转换成结构失败,string:%v, 错误:%v", v, err)
}
matchRelations = append(matchRelations, matchRelation)
}
return matchRelations, nil
}
//匹配第一帧
const matchCallReady = "match_call_ready_{matchUid}"
func GetPrefixMatchCycle(cycle int64) string {
return strings.Replace(matchCallReady, "{matchUid}", strconv.Itoa(int(cycle)), -1)
}
//推荐用户, 记录起来,用户算法中心获取。
const recommendUser = "recommend_user"
func GetPreRecommendUser() string {
return recommendUser
}
//匹配的工会用户
const matchTradeUnion = "match_trade_union_{version}"
func GetPreMatchTradeUnion(version string) string {
return strings.Replace(matchTradeUnion, "{version}", version, -1)
}
//匹配,用户信息
const matchUserKey = "match_user_{version}"
func GetPrefixMatchUser(version string) string {
return strings.Replace(matchUserKey, "{version}", version, -1)
}
//匹配,质量分数
const matchExcellent = "match_excellent_{version}"
func GetPrefixMatchExcellent(version string) string {
return strings.Replace(matchExcellent, "{version}", version, -1)
}
//匹配,用户优先度排序
const matchPriority = "match_priority_{version}"
func GetPrefixMatchPriority(version string) string {
return strings.Replace(matchPriority, "{version}", version, -1)
}
//匹配,关系分数
const matchRelation = "match_relation_{version}_{userId}"
func GetPrefixMatchRelation(version string, userId string) string {
return strings.Replace(strings.Replace(matchRelation, "{version}", version, -1), "{userId}", userId, -1)
}
//匹配,拉黑名单
const matchBlock = "match_block_{version}"
func GetPrefixMatchBlock(version string) string {
return strings.Replace(matchBlock, "{version}", version, -1)
}
//匹配,条件性别
const matchConditionSex = "match_condition_sex_{version}"
func GetPrefixMatchConditionSex(version string) string {
return strings.Replace(matchConditionSex, "{version}", version, -1)
}
//匹配,条件国家
const matchConditionCountry = "match_condition_country_{version}"
func GetPrefixMatchConditionCountry(version string) string {
return strings.Replace(matchConditionCountry, "{version}", version, -1)
}
// GetRecommendCache 获取推荐人信息
func GetRecommendCache() ([]RecommendUserCache, error) {
//获取推荐人信息缓存
key := GetPreRecommendUser()
strs, err := redisCli.RedisClient.HVals(context.Background(), key).Result()
if err != nil {
return nil, err
}
var recommendUserCaches []RecommendUserCache
for i := 0; i < len(strs); i++ {
var recommendUserCache RecommendUserCache
if err := json.Unmarshal([]byte(strs[i]), &recommendUserCache); err != nil {
mylogrus.MyLog.Errorf("match cache recommendUserCache 转换成结构失败,string:%v, 错误:%v", strs[i], err)
}
recommendUserCaches = append(recommendUserCaches, recommendUserCache)
}
return recommendUserCaches, nil
}
func GetMatchTradeUnionCache(version string) ([]MatchTradeUnionCache, error) {
key := GetPreMatchTradeUnion(version)
strs, err := redisCli.RedisClient.HVals(context.Background(), key).Result()
if err != nil {
return nil, err
}
var matchTradeUnionCaches []MatchTradeUnionCache
for i := 0; i < len(strs); i++ {
var matchTradeUnionCache MatchTradeUnionCache
if err := json.Unmarshal([]byte(strs[i]), &matchTradeUnionCache); err != nil {
mylogrus.MyLog.Errorf("match cache matchTradeUnionCache 转换成结构失败,string:%v, 错误:%v", strs[i], err)
}
matchTradeUnionCaches = append(matchTradeUnionCaches, matchTradeUnionCache)
}
return matchTradeUnionCaches, nil
}
func (matchCycle *MatchCycle) CheckBlock(userId string, otherUserId string) (bool, error) {
key := GetPrefixMatchBlock(matchCycle.cycle)
u, _ := strconv.ParseUint(userId, 10, 64)
o, _ := strconv.ParseUint(otherUserId, 10, 64)
if u > o {
flag, err := redisCli.RedisClient.SIsMember(context.Background(), key, userId+"_"+otherUserId).Result()
if err != nil {
return flag, err
}
return flag, err
} else {
flag, err := redisCli.RedisClient.SIsMember(context.Background(), key, otherUserId+"_"+userId).Result()
if err != nil {
return flag, err
}
return flag, err
}
}
func (matchCycle *MatchCycle) GetConditionSex(userId string) (string, error) {
key := GetPrefixMatchConditionSex(matchCycle.cycle)
str, err := redisCli.RedisClient.HGet(context.Background(), key, userId).Result()
if err != nil {
return "", nil
}
return str, nil
}
func (matchCycle *MatchCycle) GetConditionCountry(userId string) (string, error) {
key := GetPrefixMatchConditionCountry(matchCycle.cycle)
str, err := redisCli.RedisClient.HGet(context.Background(), key, userId).Result()
if err != nil {
return "", nil
}
return str, nil
}
package common
import (
"encoding/binary"
"errors"
"fmt"
"hash/crc32"
"time"
)
const (
MsgTypeLogin = 1 + iota
MsgTypeLoginRsp
MsgTypeHeartBeat
MsgTypeHeartBeatRsp
MsgTypeKickUser
MsgTypeBiz = 7
MsgTypeBizRsp
)
const (
MsgTypeMatchSuccess = 100 + iota
MsgTypeMatchConfirm
MsgTypeCallReady
MsgTypeAddTimeGift
MsgTypeAddTimeFree
)
const (
MsgTypeRecallWindow = 109
MsgTypeVideo = 110 // 1v1视频-v1-黄钻
MsgTypeVideoCallReady = 111
MsgTypeLikeEach = 112
MsgTypeLikeMe = 113
MsgTypeDailyInAppDiamond = 114
MsgTypeGlobalGiftBanner = 115 // 礼物横幅
MsgTypeGlobalGiftBannerRsp = 116
MsgTypeLuckyWheel = 117 //已丢弃
MsgTypeLuckyWheelBanner = 118
MsgTypeDiamondChange = 119 // Kludge:事实上是通用的钻石变更通知了
MsgTypeConfigChange = 120 // 配置变更通知
MsgTypeGlobalRocketNotice = 121 // 火箭全局横幅
MsgTypeGroupChatNotice = 122 // 群发消息弹窗
MsgTypeGlobalBroadcast = 123 // 群发消息弹窗
MsgMicTaskFinish = 124 // 麦上任务完成
MsgFruitMachine = 125 // 水果机开奖
MsgTypeNobleChange = 126 // 贵族变更
MsgTypeJoinGroup = 127 // 加入群组成功
MsgTypeVideoTimeMinuteSuccess = 128 // 1对1视频加时成功
MsgTypeVideoTimeMinuteCheck = 129 // 1对1视频加时检查
MsgTypeVideoMiss = 130 // 1对1视频错过
MsgTypeRoomGroupActivity = 131 // 进房,群组活动推送
MsgTypeVideoV2 = 132 // 1v1视频-v2-粉钻
MsgTypeVideoV2TimeMinuteCheck = 133 // 1v1视频-v2-加时检查
MsgTypeVideoV2CallReady = 134 // 1v1视频-v2-callReady
MsgTypeVideoV2TimeMinuteSuccess = 135 // 1v1视频-v2-加时成功
MsgTypeMatchV2Success = 140 // 匹配-v2-成功
MsgTypeMatchV2Confirm = 141 // 匹配-v2-确认
MsgTypeMatchV2CallReady = 142 // 匹配-v2-callReady
MsgTypeMatchV2AddTimeGift = 143 // 匹配-v2-送礼加时长
)
const (
RoomBannerChange = 1 // 房间banner变更
GiftConfigChange = 2 // 礼物配置变更
OpenScreenChange = 3 // 开屏配置变更
MatchConfigChange = 4 // 匹配配置发生了变化
)
func EncodeMessage(msgType uint32, serialNum uint64, userdata []byte) []byte {
msg := make([]byte, 26)
dataLen := len(userdata)
binary.BigEndian.PutUint16(msg, 1)
binary.BigEndian.PutUint32(msg[2:], msgType)
binary.BigEndian.PutUint64(msg[6:], serialNum)
binary.BigEndian.PutUint64(msg[14:], uint64(time.Now().UnixNano()/1000))
binary.BigEndian.PutUint32(msg[22:], uint32(dataLen))
msg = append(msg, userdata...)
checkSum := crc32.ChecksumIEEE(msg)
msg = append(msg, 0, 0, 0, 0)
binary.BigEndian.PutUint32(msg[26+dataLen:], checkSum)
return msg
}
func DecodeMessage(message []byte) (uint32, uint64, uint64, []byte, error) {
length := len(message)
// 保证消息至少有26bytes
if length >= 26 {
//version := binary.BigEndian.Uint16(message[0:2])
msgType := binary.BigEndian.Uint32(message[2:6])
msgId := binary.BigEndian.Uint64(message[6:14])
timeStamp := binary.BigEndian.Uint64(message[14:22])
dataLen := binary.BigEndian.Uint32(message[22:26])
//log.Printf("DecodeMessage version = %d, msgType = %d, msgId = %d, timeStamp = %d, dataLen = %d\n", version, msgType, msgId, timeStamp, dataLen)
// 保证ws消息至少有msgLen长
if uint32(length) >= dataLen+30 {
pbData := message[26 : dataLen+26]
checksum := binary.BigEndian.Uint32(message[dataLen+26 : dataLen+30])
//fmt.Printf("pbData size = %d, checksum = %d\n", len(pbData), checksum)
myCheckSum := crc32.ChecksumIEEE(message[0 : dataLen+26])
if checksum != myCheckSum {
return 0, msgId, timeStamp, nil, errors.New("checksum error")
}
return msgType, msgId, timeStamp, pbData, nil
} else {
fmt.Printf("payload too short length = %d, msgType = %d\n", length, msgType)
return 0, msgId, timeStamp, nil, errors.New("payload too short")
}
} else {
fmt.Printf("message too short for header %d\n ", length)
return 0, 0, 0, nil, errors.New("message too short")
}
}
package config
import (
"github.com/joho/godotenv"
"github.com/sirupsen/logrus"
"gopkg.in/ini.v1"
"os"
"runtime"
"strconv"
)
//数据库的配置
type MysqlConfig struct {
MYSQL_HOST string
MYSQL_USERNAME string
MYSQL_PASSWORD string
MYSQL_DB string
}
type MysqlCodeConfig struct {
MYSQL_HOST string
MYSQL_USERNAME string
MYSQL_PASSWORD string
MYSQL_DB string
}
//redis配置
type RedisConfig struct {
REDIS_HOST string
REDIS_PASSWORD string
}
//jwt
type JwtConfig struct {
SECRET string
ISSUER_API string
ISSUER_MGR string
EXPIRE string
}
//oss
type OssConfig struct {
OSS_ACCESS_KEY_ID string
OSS_ACCESS_KEY_SECRET string
OSS_ROLE_ARN string
OSS_END_POINT string
OSS_BUCKET string
OSS_CDN string
OSS_EXPIRED_TIME uint
OSS_STS_POINT string
OSS_STS string
OSS_STS_AES string
}
// aws
type AwsConfig struct {
AWS_BUCKET string
AWS_CDN string
AWS_DIR string
CONFIDENCE float32
}
//APP
type AppConfig struct {
BIZ_SECRET string
WEB_SECRET string
OPERATION_SECRET string
SUPERUSER string
OFFICIAL_GROUP string
MINIMAL_VERSION_ANDROID int
MINIMAL_VERSION_IOS int
MODERATE string
}
//googlePay 配置信息
type GooglePayConfig struct {
JsonKey []byte
}
//融云
type RongyunConfig struct {
RONG_CLOUD_APP_KEY string
RONG_CLOUD_APP_SECRET string
RONG_CLOUD_URL string
}
//腾讯云
type TencentyunConfig struct {
TENCENTYUN_APP_ID int
TENCENTYUN_KEY string
TX_OVERSEA_APP_ID int
TX_OVERSEA_KEY string
}
//emas
type EmasConfig struct {
ANDROID_APP_KEY string
ANDROID_APP_SECRET string
REGION_ID string
ACCESS_KEY_ID string
ACCESS_KEY_SECRET string
IOS_APP_KEY string
IOS_APP_SECRET string
APNS string
}
//声网
type AgoraConfig struct {
APP_ID string
APP_CERTIFICATE string
CUSTOMER_KEY string
CUSTOMER_SECRET string
}
//匹配的配置
type MatchConfig struct {
//一开始匹配的默认时长(单位:秒)
MATCH_FREE_TIME int
//一开始匹配的默认时长(单位:秒)VIP
MATCH_FREE_TIME_VIP int
//免费加时的时长 (单位:秒)
MATCH_ADD_TIME_FREE int
//匹配的声网的延迟加时(单位:秒)
MATCH_AGORA_TIME int
//匹配周期(单位:秒)
MATCH_CYCLE int
//过期时间(单位:秒),用户redisCache时间
MATCH_USER_EXPIRES int
//pb match_success中, wait_duration 开始/下一个时间(单位:秒)
MATCH_SUCCESS_WAIT_DURATION uint32
//pb match_success中, single_wait_time_in_sec 单方等待连接最长时间(单位:秒)
MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC uint32
//pb match_success中, dual_wait_time_in_sec 双方连接中最长时间(单位:秒)
MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC uint32
}
//在线
type OnlineConfig struct {
//在线周期
ONLINE_CYCLE int
//在线过期时间
ONLINE_USER_EXPIRES int
}
//1对1视频
type VideoConfig struct {
VIDEO_DAILY_FREE_NUM int
//一开始匹配的默认时长(单位:秒)
VIDEO_FREE_TIME int
//一开始匹配的默认时长(单位:秒),vip
VIDEO_FREE_TIME_VIP int
//免费加时的时长 (单位:秒)
VIDEO_ADD_TIME_FREE int
//声网的延迟加时(单位:秒)
VIDEO_AGORA_TIME int
//1分钟视频,普通用户价格
VIDEO_MINUTE_NORMAL int
//1分钟视频,公会用户价格
VIDEO_MINUTE_UNION int
}
//会话
type SessionConfig struct {
SESSION_DAILY_FREE_NUM int
GUILD_USER_HELLO_DAY int
}
type BeanConfig struct {
DIAMOND_BEAN_RATE int
}
type H5Config struct {
USER_LEVEL string
GROUP_SUPPORT string
LUCKY_WHEEL string
WEEKLY_STAR string
WEEKLY_CP string
COUNTRY_STAR string
NOBLE_BUY_IOS string
NOBLE_BUY_IOS_AUDIT string
GUILD_DATA_URL string
MGR_GUILD_DATA_URL string
RANKING_PINK_DIAMOND_URL string
GROUP_POWER_GRADE_URL string
GROUP_POWER_ACT_URL string
SHEEP_H5_URL string
}
type GroupImConfig struct {
MSG_SORT_EXPIRE int
MSG_SORT_SNAP int
MSG_PARALLEL_SIZE int
}
type GradeConfig struct {
//魅力速度
CHARM_SPEED_VIP int
//活跃
ACTITY_SPEED_VIP int
//财富
WEALTH_SPEED_VIP int
}
type LikeConfig struct {
//喜欢人数
I_LIKE_NUM int
//喜欢人数VIP
I_LIKE_NUM_VIP int
//喜欢人数贵族
I_LIKE_NUM_NOBLE int
}
type ApplePayConfig struct {
PASSWORD string
}
type RegisterConfig struct {
IMEI_TOTAL int
IMEI_OAUTH int
ACCOUNT_IP int
ACCOUNT_IP_DURATION int
}
type BannerConfig struct {
GIFT_BANNER_LEVEL1 int
GIFT_BANNER_LEVEL2 int
GIFT_BANNER_LEVEL3 int
}
type DiamondConfig struct {
DAILY_LOGIN_IMEI_LIMIT int
DAILY_LOGIN_IP_LIMIT int
PRIVATE_GIFT_RETURN int
NEW_USER_INVITE_AWARD uint32
}
type LuckWheelConfig struct {
MINIMAL_PARTICIPANT int // 轮盘开始最少需要的参与人数
WAIT_TIMELONG int // 等待轮盘开始的时长(分钟)
WINNER_DIAMOND_BANNER int //全服广播钻石门槛
}
//自定义主题
type GroupCustomThemeConfig struct {
PIC_LIMIT int //图片数量
DAY int //有效天数
}
type GiftConfig struct {
WALL_DIAMOND int //上礼物墙,礼物钻石金额
}
type DailyConfig struct {
LOGIN_COMMON int
LOGIN_VIP int
}
type FruitTycoonConfig struct {
BIG_WINNER_THRESDHOLD uint
BIG_WINNER_LOW uint
BIG_WINNER_HIGH uint
POOL_RATIO uint32
WATERMELON_RATIO uint32
}
type ActivityConfig struct {
COUNTRY_STAR_POOL_RATIO uint32
COUNTRY_STAR_ORDINARY_RATIO uint32
}
type CheckoutConfig struct {
URL string
AUTHORIZATION string
H5 string
HILO_SECRET_KEY string
}
type RiskControlConfig struct {
USER_QPS_LIMIT int64
USER_URL_QPS_LIMIT int64
}
type PayerMaxConfig struct {
URL string
KEY string
MERCHANT_ID string
BIZ_TYPE string
VERSION string
FRONT_CALLBACK_URL string
SHOW_RESULT string
EXPIRE_TIME string
LANGUAGE string
}
type PaypalConfig struct {
PAYPAL_CLIENT_ID string
PAYPAL_SECRET_ID string
RETURN_URL string
}
const (
LOCAL string = "local"
DEBUG string = "debug"
RELEASE string = "release"
)
var mysqlConfigData MysqlConfig
var mysqlCodeConfigData MysqlCodeConfig
var redisConfigData RedisConfig
var jwtConfigData JwtConfig
var appConfigData AppConfig
var ossConfigData OssConfig
var awsConfigData AwsConfig
var googlePayData GooglePayConfig
var rongyunData RongyunConfig
var tencentyunData TencentyunConfig
var emasData EmasConfig
var agora AgoraConfig
var matchData MatchConfig
var onlineData OnlineConfig
var sessionData SessionConfig
var videoData VideoConfig
var beanData BeanConfig
var h5Data H5Config
var groupImData GroupImConfig
var gradeData GradeConfig
var likeData LikeConfig
var applePayData ApplePayConfig
var registerData RegisterConfig
var bannerConfig BannerConfig
var diamondConfig DiamondConfig
var luckyWheelConfig LuckWheelConfig
var groupCustomThemeConfig GroupCustomThemeConfig
var giftConfig GiftConfig
var dailyConfig DailyConfig
var fruitTycoonConfig FruitTycoonConfig
var activityConfig ActivityConfig
var checkoutConfig CheckoutConfig
var riskControl RiskControlConfig
var payerMaxConfig PayerMaxConfig
var paypalConfig PaypalConfig
var mode string
var master bool
func GetConfigMysql() MysqlConfig {
return mysqlConfigData
}
func GetConfigMysqlCode() MysqlCodeConfig {
return mysqlCodeConfigData
}
func GetConfigRedis() RedisConfig {
return redisConfigData
}
func GetConfigJWT() JwtConfig {
return jwtConfigData
}
func GetConfigApp() AppConfig {
return appConfigData
}
func GetConfigOss() OssConfig {
return ossConfigData
}
func GetConfigAws() AwsConfig {
return awsConfigData
}
func GetConfigGooglePay() GooglePayConfig {
return googlePayData
}
func GetMode() string {
return mode
}
func AppIsRelease() bool {
return GetMode() == RELEASE
}
func AppIsLocal() bool {
return GetMode() == LOCAL
}
func IsMaster() bool {
return master
}
func GetOssCDN() string {
return ossConfigData.OSS_CDN
}
func GetRongyunAppKey() string {
return rongyunData.RONG_CLOUD_APP_KEY
}
func GetRongyunAppSecret() string {
return rongyunData.RONG_CLOUD_APP_SECRET
}
func GetRongyunUrl() string {
return rongyunData.RONG_CLOUD_URL
}
func GetTencentyunAppId() int {
return tencentyunData.TENCENTYUN_APP_ID
}
func GetTencentyunKey() string {
return tencentyunData.TENCENTYUN_KEY
}
func GetTxOverSeaAppId() int {
return tencentyunData.TX_OVERSEA_APP_ID
}
func GetTxOverSeaAppKey() string {
return tencentyunData.TX_OVERSEA_KEY
}
func GetEmasRegionId() string {
return emasData.REGION_ID
}
func GetEmasAccessKeyId() string {
return emasData.ACCESS_KEY_ID
}
func GetEmasAccessKeySecret() string {
return emasData.ACCESS_KEY_SECRET
}
func GetEmasAndroidAppKey() string {
return emasData.ANDROID_APP_KEY
}
func GetEmasIosAppKey() string {
return emasData.IOS_APP_KEY
}
func GetEmasApns() string {
return emasData.APNS
}
func GetAgoraAppId() string {
return agora.APP_ID
}
func GetAgoraAppCertificate() string {
return agora.APP_CERTIFICATE
}
func GetAgoraCustomerKey() string {
return agora.CUSTOMER_KEY
}
func GetAgoraCustomerSecret() string {
return agora.CUSTOMER_SECRET
}
func GetMatchConfig() *MatchConfig {
return &matchData
}
func GetOnlineConfig() *OnlineConfig {
return &onlineData
}
func GetSessionConfig() SessionConfig {
return sessionData
}
func GetVideoConfig() VideoConfig {
return videoData
}
func GetBeanConfig() BeanConfig {
return beanData
}
func GetH5Config() H5Config {
return h5Data
}
func GetGroupImConfig() GroupImConfig {
return groupImData
}
func GetGradeConfig() GradeConfig {
return gradeData
}
func GetLikeConfig() LikeConfig {
return likeData
}
func GetApplePayConfig() ApplePayConfig {
return applePayData
}
func GetRegisterConfig() RegisterConfig {
return registerData
}
func GetBannerConfig() BannerConfig {
return bannerConfig
}
func GetDiamondConfig() DiamondConfig {
return diamondConfig
}
func GetLuckyWheelConfig() LuckWheelConfig {
return luckyWheelConfig
}
func GetGroupCustomThemeConfig() GroupCustomThemeConfig {
return groupCustomThemeConfig
}
func GetGiftConfig() GiftConfig {
return giftConfig
}
func GetDailyConfig() DailyConfig {
return dailyConfig
}
func GetFruitTycoonConfig() FruitTycoonConfig {
return fruitTycoonConfig
}
func GetActivityConfig() ActivityConfig {
return activityConfig
}
func GetCheckoutConfig() CheckoutConfig {
return checkoutConfig
}
func GetRiskControlConfig() RiskControlConfig {
return riskControl
}
func GetPayerMaxConfig() PayerMaxConfig {
return payerMaxConfig
}
func GetPaypalConfig() PaypalConfig {
return paypalConfig
}
func init() {
str, _ := os.Getwd()
logrus.New().Info(str)
envDir := ".env"
//加载环境变量
if err := godotenv.Load(envDir); err != nil {
logrus.New().Fatalf("Error loading .env err:%v", err)
}
//获取环境变量
mode = os.Getenv("MODE")
var err error
master, _ = strconv.ParseBool(os.Getenv("MASTER"))
logrus.New().Infof("My role is %t", master)
iniDir := mode + ".ini"
if runtime.GOOS == "darwin" { // mac本地调试
iniDir = "/var/log/hilo/" + iniDir
}
//根据环境变量获取具体的配置,实现多环境配置
//var conf *ini.File
conf, err := ini.LoadSources(ini.LoadOptions{IgnoreInlineComment: true}, iniDir)
if err != nil {
logrus.New().Fatal(err)
}
//加载mysql的配置
if err := conf.Section("DATABASE").MapTo(&mysqlConfigData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("DATABASECODE").MapTo(&mysqlCodeConfigData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("REDIS").MapTo(&redisConfigData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("JWT").MapTo(&jwtConfigData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("APP").MapTo(&appConfigData); err != nil {
logrus.New().Fatal(err)
} else {
logrus.New().Infof("APP: %+v", appConfigData)
}
if err := conf.Section("OSS").MapTo(&ossConfigData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("AWS").MapTo(&awsConfigData); err != nil {
logrus.New().Fatal(err)
} else {
if awsConfigData.CONFIDENCE <= 50 {
awsConfigData.CONFIDENCE = 80
}
logrus.New().Infof("AWS: %+v", awsConfigData)
}
if err := conf.Section("RONGYUN").MapTo(&rongyunData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("TENCENTYUN").MapTo(&tencentyunData); err != nil {
logrus.New().Fatal(err)
} else {
logrus.New().Info("TENCENTYUN: ", tencentyunData)
}
if err := conf.Section("EMAS").MapTo(&emasData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("AGORA").MapTo(&agora); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("MATCH").MapTo(&matchData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("ONLINE").MapTo(&onlineData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("SESSION").MapTo(&sessionData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("VIDEO").MapTo(&videoData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("BEAN").MapTo(&beanData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("H5").MapTo(&h5Data); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("GROUPIM").MapTo(&groupImData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("GRADE").MapTo(&gradeData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("LIKE").MapTo(&likeData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("APPLEPAY").MapTo(&applePayData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("REGISTER").MapTo(&registerData); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("BANNER").MapTo(&bannerConfig); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("DIAMOND").MapTo(&diamondConfig); err != nil {
logrus.New().Fatal(err)
} else {
if diamondConfig.NEW_USER_INVITE_AWARD <= 0 {
diamondConfig.NEW_USER_INVITE_AWARD = 5000
}
}
if err := conf.Section("LUCKY_WHEEL").MapTo(&luckyWheelConfig); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("GROUP_CUSTOM_THEME").MapTo(&groupCustomThemeConfig); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("GIFT").MapTo(&giftConfig); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("DAILY").MapTo(&dailyConfig); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("CHECKOUT").MapTo(&checkoutConfig); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("PAYER_MAX").MapTo(&payerMaxConfig); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("PAYPAL").MapTo(&paypalConfig); err != nil {
logrus.New().Fatal(err)
}
if err := conf.Section("FRUIT_TYCOON").MapTo(&fruitTycoonConfig); err != nil {
logrus.New().Fatal(err)
} else {
// 防止未配置或配置错误
if fruitTycoonConfig.BIG_WINNER_LOW <= 0 {
fruitTycoonConfig.BIG_WINNER_LOW = 10000
}
if fruitTycoonConfig.BIG_WINNER_HIGH <= 0 {
fruitTycoonConfig.BIG_WINNER_HIGH = 20000
}
if fruitTycoonConfig.POOL_RATIO <= 0 || fruitTycoonConfig.POOL_RATIO > 100 {
fruitTycoonConfig.POOL_RATIO = 20
}
if fruitTycoonConfig.WATERMELON_RATIO <= 0 || fruitTycoonConfig.WATERMELON_RATIO > 100 {
fruitTycoonConfig.WATERMELON_RATIO = 70
}
logrus.New().Infof("FRUIT_TYCOON: %+v", fruitTycoonConfig)
}
if err := conf.Section("ACTIVITY").MapTo(&activityConfig); err != nil {
logrus.New().Fatal(err)
} else {
// 防止未配置或配置错误
if activityConfig.COUNTRY_STAR_POOL_RATIO <= 0 {
activityConfig.COUNTRY_STAR_POOL_RATIO = 20
}
if activityConfig.COUNTRY_STAR_ORDINARY_RATIO <= 0 {
activityConfig.COUNTRY_STAR_ORDINARY_RATIO = 20
}
logrus.New().Infof("ACTIVITY: %+v", activityConfig)
}
if err := conf.Section("RISK_CONTROL").MapTo(&riskControl); err != nil {
logrus.New().Fatal(err)
} else {
if riskControl.USER_QPS_LIMIT <= 0 {
riskControl.USER_QPS_LIMIT = 128
}
if riskControl.USER_URL_QPS_LIMIT <= 0 {
riskControl.USER_URL_QPS_LIMIT = 64
}
logrus.New().Infof("RISK_CONTROL: %+v", riskControl)
}
}
package consul
import (
"fmt"
"github.com/hashicorp/consul/api"
"math/rand"
"strconv"
)
func GetAgentInfo(client *api.Client) (string, string) {
info, err := client.Agent().Self()
if err != nil {
fmt.Printf("%v\n", err)
return "", ""
}
if info == nil {
fmt.Println("Fail to get consul info.")
return "", ""
}
ip := ""
inter := info["DebugConfig"]["AdvertiseAddrLAN"]
switch inter.(type) {
case string:
ip = inter.(string)
break
}
nodeName := ""
inter = info["Config"]["NodeName"]
switch inter.(type) {
case string:
nodeName = inter.(string)
break
}
return ip, nodeName
}
func SelectService(cataLog *api.Catalog, serviceName string, nodeName string) (string, error) {
services, _, err := cataLog.Service(serviceName, "", nil)
if err != nil {
return "", err
}
if len(services) == 0 {
fmt.Println("userCenter not found in catalog.")
return "", nil
}
var count int32 = 0
addr := ""
for _, s := range services {
fmt.Printf("service info: %v\n", s)
if s.ServiceWeights.Passing == 1 {
count++
if s.Node == nodeName {
addr = s.ServiceAddress + ":" + strconv.Itoa(s.ServicePort)
break
} else {
if rand.Int31n(count) == 0 {
addr = s.ServiceAddress + ":" + strconv.Itoa(s.ServicePort)
}
}
}
}
return addr, nil
}
func GetServices(cataLog *api.Catalog, serviceName string) ([]string, error) {
addrs := make([]string, 0)
services, _, err := cataLog.Service(serviceName, "", nil)
if err == nil {
for _, s := range services {
fmt.Printf("service info: %s, %s, %s:%d", s.ID, s.Node, s.ServiceAddress, s.ServicePort)
if s.ServiceWeights.Passing == 1 {
addrs = append(addrs, s.ServiceAddress+":"+strconv.Itoa(s.ServicePort))
}
}
}
return addrs, nil
}
package mylogrus
import (
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
"github.com/rifflock/lfshook"
"github.com/sirupsen/logrus"
"hilo-algoCenter/common/config"
"io"
"os"
"path/filepath"
"time"
)
const logDir = "/var/log/hilo/"
var filenamePrefix string
var MyLog = logrus.New()
func Info(v interface{}) {
MyLog.Info("")
}
func init() {
filenamePrefix = logDir + filepath.Base(os.Args[0]) + "."
//if runtime.GOOS == "darwin" { // mac本地调试
// filenamePrefix = "./log/hilo/" + filepath.Base(os.Args[0]) + "."
//}
// stderr日志重定向
MyLog.SetOutput(os.Stdout)
RewriteStderrFile()
if config.AppIsRelease() {
MyLog.SetFormatter(&logrus.JSONFormatter{
DisableHTMLEscape: true,
TimestampFormat: "2006-01-02 15:04:05.000",
})
hook := lfshook.NewHook(lfshook.WriterMap{
logrus.DebugLevel: getLevelWrite(logrus.DebugLevel),
logrus.InfoLevel: getLevelWrite(logrus.InfoLevel),
logrus.WarnLevel: getLevelWrite(logrus.WarnLevel),
logrus.ErrorLevel: getLevelWrite(logrus.ErrorLevel),
logrus.FatalLevel: getLevelWrite(logrus.FatalLevel),
logrus.PanicLevel: getLevelWrite(logrus.PanicLevel),
}, &logrus.JSONFormatter{DisableHTMLEscape: true, TimestampFormat: time.RFC3339Nano})
MyLog.AddHook(hook)
MyLog.SetLevel(logrus.InfoLevel)
MyLog.SetReportCaller(true)
} else {
MyLog.SetFormatter(&logrus.TextFormatter{
ForceQuote: false,
DisableQuote: true,
TimestampFormat: "2006-01-02 15:04:05.000",
FullTimestamp: true,
})
hook := lfshook.NewHook(lfshook.WriterMap{
logrus.DebugLevel: getLevelWrite(logrus.DebugLevel),
logrus.InfoLevel: getLevelWrite(logrus.InfoLevel),
logrus.WarnLevel: getLevelWrite(logrus.WarnLevel),
logrus.ErrorLevel: getLevelWrite(logrus.ErrorLevel),
logrus.FatalLevel: getLevelWrite(logrus.FatalLevel),
logrus.PanicLevel: getLevelWrite(logrus.PanicLevel),
}, &logrus.TextFormatter{ForceQuote: false, DisableQuote: true, TimestampFormat: time.RFC3339Nano})
MyLog.AddHook(hook)
MyLog.SetLevel(logrus.InfoLevel)
MyLog.SetReportCaller(true)
}
}
func GetInfoLog() io.Writer {
return getLevelWrite(logrus.InfoLevel)
}
func getLevelWrite(level logrus.Level) io.Writer {
var name string
switch level {
case logrus.DebugLevel:
name = "debug.log"
case logrus.InfoLevel:
name = "info.log"
case logrus.WarnLevel:
name = "warn.log"
case logrus.ErrorLevel:
name = "error.log"
case logrus.FatalLevel:
name = "fatal.log"
case logrus.PanicLevel:
name = "panic.log"
}
name = filenamePrefix + name
writer, err := rotatelogs.New(
name+".%Y%m%d%H",
rotatelogs.WithLinkName(name), // 生成软链,指向最新日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
rotatelogs.WithRotationTime(time.Hour), // 日志切割时间间隔
)
if err != nil {
MyLog.Fatal("Failed to create log file:", err.Error())
}
return writer
}
func GetSqlLog() io.Writer {
//if !config.AppIsRelease() {
// return GetInfoLog()
//}
//name := filenamePrefix + "sql.log"
//file, err := os.OpenFile(name, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
//if err == nil {
// return file
//} else {
// MyLog.Fatal("Failed to create sql log file:", err.Error())
//}
var name string = "sql.log"
name = filenamePrefix + name
writer, err := rotatelogs.New(
name+".%Y%m%d%H",
rotatelogs.WithLinkName(name), // 生成软链,指向最新日志文件
rotatelogs.WithMaxAge(7*24*time.Hour), // 文件最大保存时间
rotatelogs.WithRotationTime(time.Hour), // 日志切割时间间隔
)
if err != nil {
MyLog.Fatal("Failed to create log file:", err.Error())
}
return writer
}
//go:build !windows
// +build !windows
package mylogrus
import (
"fmt"
"os"
"path/filepath"
"runtime"
"syscall"
"time"
)
var stdErrFileHandler *os.File
func RewriteStderrFile() {
filename := logDir + filepath.Base(os.Args[0]) + ".stderr.log"
//if runtime.GOOS == "darwin" { // mac本地调试
// filename = "./log/hilo/" + filepath.Base(os.Args[0]) + ".stderr.log"
//}
if exits, _ := pathExists(filename); exits {
os.Rename(filename, filename+"_"+time.Now().Format("20060102150405"))
}
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
if err != nil {
fmt.Println(err)
return
}
stdErrFileHandler = file //把文件句柄保存到全局变量,避免被GC回收
if err = syscall.Dup2(int(file.Fd()), int(os.Stderr.Fd())); err != nil {
fmt.Println(err)
return
}
// 内存回收前关闭文件描述符
runtime.SetFinalizer(stdErrFileHandler, func(fd *os.File) {
fd.Close()
})
return
}
func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
//go:build windows
// +build windows
package mylogrus
import (
"os"
"path/filepath"
"time"
)
func RewriteStderrFile() {
filename := logDir + filepath.Base(os.Args[0]) + ".stderr.log"
if exits, _ := pathExists(filename); exits {
os.Rename(filename, filename+"_"+time.Now().Format("20060102150405"))
}
file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0666)
MyLog.Errorf("stderr log in:%v,err:%v", file, err)
}
func pathExists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
package mysql
import (
"strconv"
)
/**
基于PDM,建立统计的数据domain结构。注意,不要选择0, 因为go的int默认值为0
*/
//主键ID
type ID = uint64
//性别
type Sex = uint8
//加减
type AddReduce = uint8
//拥有
type YesNo = uint8
//短描述
type Str = string
//时间戳
type Time = int64
//状态
type UserYesNo = uint8
//平台
type Platform = uint8
//多枚举类型
type Type = uint8
//数量
type Num = uint32
//时间戳
type Timestamp = uint64
//排序
type Index = uint16
//数量,并且用到-1作为特殊标记位
type NumAll = int
//开启关闭
type OpenClose = uint8
//逻辑删除
type LogicDel = uint8
//设备
type Device = uint8
type PeriodType = uint8
type FinishYesNo = uint8
type PayOrderType = uint8
//性别
const (
MAN Sex = 1
WOMAN Sex = 2
EMPTY Sex = 0
)
//yes no
const (
YES YesNo = 1
NO YesNo = 2
)
const (
OPEN OpenClose = 1
CLOSE OpenClose = 2
)
//加,减
const (
ADD AddReduce = 1
REDUCE AddReduce = 2
NilAddREDUCE AddReduce = 3
)
const (
USER UserYesNo = 1
NOUSER UserYesNo = 2
)
const (
Apple Platform = 1
GOOGLE Platform = 2
EGG_PLANT Platform = 3 // 通过starchat回调的茄子充值 代理充值
Checkout Platform = 4
PayerMax Platform = 5 // 通过hilo发起,starchat回调的PayerMax/茄子充值
Paypal Platform = 6 // paypal
ApplePink Platform = 31 // Apple pay 购买粉钻
GOOGLEPink Platform = 32 // GOOGLE pay 购买粉钻
PayTypeZero PayOrderType = 0 //
PayTypeProxy PayOrderType = 1 // 1.代理给自己充值
PayTypeUserToProxy PayOrderType = 2 // 2.用户给代理充值
CheckoutName = "cheakout支付"
PayerMaxName = "茄子支付"
PayPalName = "PayPal支付"
)
//逻辑删除
const (
EXIST LogicDel = 1
DEL LogicDel = 2
)
const (
DAY PeriodType = 1
Week PeriodType = 2
Month PeriodType = 3
Year PeriodType = 4
)
const (
FinishNo FinishYesNo = 0
FinishYes FinishYesNo = 1
)
const (
DiamondYellow Type = 1
DiamondPink Type = 2
)
func IdToStr(id ID) string {
return strconv.Itoa(int(id))
}
func StrToId(id string) (ID, error) {
var idInt int
var err error
if idInt, err = strconv.Atoi(id); err != nil {
return 0, err
}
return ID(idInt), nil
}
func NumToString(num Num) string {
return strconv.Itoa(int(num))
}
func TypeToString(t Type) string {
return strconv.Itoa(int(t))
}
func StrToType(t string) (Type, error) {
var tInt int
var err error
if tInt, err = strconv.Atoi(t); err != nil {
return 0, err
}
return Type(tInt), nil
}
/*func IdToUint64(id ID) uint64 {
return uint64(id)
}*/
func IdsToUint64(ids []ID) []uint64 {
uints := []uint64{}
for i := 0; i < len(ids); i++ {
uints = append(uints, uint64(ids[i]))
}
return uints
}
package mysql
import "time"
type EntityI interface {
GetID() ID
//用于判断数据是否进行持久化
IsLazyLoad() bool
//默认值为false true:代表要移除数据
CheckDel() bool
//检查是否唯一键冲突,依旧更新
CheckOnDuplicateKeyUPDATE() bool
//检查是否唯一键冲突,则不插入
CheckOnDuplicateKeyIGNORE() bool
//更新乐观锁 默认值为false true:乐观锁更新
CheckUpdateVersion() bool
//更新条件.
CheckUpdateCondition() bool
//获取版本号
GetUpdateVersionBefore() uint
//更新情况
GetUpdateCondition() string
//save 动作排除字段
GetOmit() []string
}
type Entity struct {
ID ID `gorm:"primary_key"`
CreatedTime time.Time `gorm:"->"`
UpdatedTime time.Time `gorm:"->"`
lazyLoad bool `gorm:"-"`
del bool `gorm:"-"`
onDuplicateKeyUPDATE bool `gorm:"-"`
onDuplicateKeyIGNORE bool `gorm:"-"`
updateVersionFlag bool `gorm:"-"`
updateVersionBefore uint `gorm:"-"`
updateCondition string `gorm:"-"`
omit []string `gorm:"-"` //更新排除
updateColumns map[string]interface{} `gorm:"-"` //更新字段
}
func (t *Entity) GetID() ID {
return t.ID
}
func (t *Entity) IsLazyLoad() bool {
return t.lazyLoad
}
func (t *Entity) SetLasyLoad() {
t.lazyLoad = true
}
func (t *Entity) SetDel() {
t.del = true
}
func (t *Entity) CheckDel() bool {
return t.del
}
func (t *Entity) SetOnDuplicateKeyUPDATE() {
t.onDuplicateKeyUPDATE = true
}
func (t *Entity) SetOnDuplicateKeyIGNORE() {
t.onDuplicateKeyIGNORE = true
}
func (t *Entity) CheckOnDuplicateKeyUPDATE() bool {
return t.onDuplicateKeyUPDATE
}
func (t *Entity) CheckOnDuplicateKeyIGNORE() bool {
return t.onDuplicateKeyIGNORE
}
func (t *Entity) SetCheckUpdateVersionBefore(versionBefore uint) {
t.updateVersionBefore = versionBefore
t.updateVersionFlag = true
}
func (t *Entity) SetCheckUpdateCondition(condition string) {
t.updateCondition = condition
}
func (t *Entity) CheckUpdateVersion() bool {
return t.updateVersionFlag
}
func (t *Entity) CheckUpdateCondition() bool {
return t.updateCondition != ""
}
func (t *Entity) GetUpdateCondition() string {
return t.updateCondition
}
func (t *Entity) GetUpdateVersionBefore() uint {
return t.updateVersionBefore
}
func (t *Entity) GetOmit() []string {
return t.omit
}
func (t *Entity) SetOmit(omit []string) {
t.omit = omit
}
func (t *Entity) SetUpdateColumns(updateColumns map[string]interface{}) {
t.updateColumns = updateColumns
}
func (t *Entity) GetUpdateColumns() map[string]interface{} {
return t.updateColumns
}
package mysql
import (
"context"
"fmt"
. "gorm.io/gorm/logger"
"gorm.io/gorm/utils"
"time"
)
func MyNew(writer Writer, config Config) Interface {
var (
infoStr = "%s[info] "
warnStr = "%s[warn] "
errStr = "%s[error] "
traceStr = "%s[%.3fms] [rows:%v] %s"
traceWarnStr = "%s %s[%.3fms] [rows:%v] %s"
traceErrStr = "%s %s[%.3fms] [rows:%v] %s"
)
//if config.Colorful {
// infoStr = Green + "%s\n" + Reset + Green + "[info] " + Reset
// warnStr = BlueBold + "%s\n" + Reset + Magenta + "[warn] " + Reset
// errStr = Magenta + "%s\n" + Reset + Red + "[error] " + Reset
// traceStr = Green + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
// traceWarnStr = Green + "%s " + Yellow + "%s\n" + Reset + RedBold + "[%.3fms] " + Yellow + "[rows:%v]" + Magenta + " %s" + Reset
// traceErrStr = RedBold + "%s " + MagentaBold + "%s\n" + Reset + Yellow + "[%.3fms] " + BlueBold + "[rows:%v]" + Reset + " %s"
//}
myTraceStr := " traceId:%v userId:%v"
infoStr += myTraceStr
warnStr += myTraceStr
errStr += myTraceStr
traceStr += myTraceStr
traceWarnStr += myTraceStr
traceErrStr += myTraceStr
return &myLogger{
Writer: writer,
Config: config,
infoStr: infoStr,
warnStr: warnStr,
errStr: errStr,
traceStr: traceStr,
traceWarnStr: traceWarnStr,
traceErrStr: traceErrStr,
}
}
type myLogger struct {
Writer
Config
infoStr, warnStr, errStr string
traceStr, traceErrStr, traceWarnStr string
}
// LogMode log mode
func (l *myLogger) LogMode(level LogLevel) Interface {
newlogger := *l
newlogger.LogLevel = level
return &newlogger
}
// Info print info
func (l myLogger) Info(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Info {
l.Printf(l.infoStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Warn print warn messages
func (l myLogger) Warn(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Warn {
l.Printf(l.warnStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Error print error messages
func (l myLogger) Error(ctx context.Context, msg string, data ...interface{}) {
if l.LogLevel >= Error {
l.Printf(l.errStr+msg, append([]interface{}{utils.FileWithLineNum()}, data...)...)
}
}
// Trace print sql message
func (l myLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) {
traceId, userId := ctx.Value("traceId"), ctx.Value("userId")
if l.LogLevel > Silent {
elapsed := time.Since(begin)
switch {
case err != nil && l.LogLevel >= Error:
sql, rows := fc()
if rows == -1 {
l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceErrStr, utils.FileWithLineNum(), err, float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
case elapsed > l.SlowThreshold && l.SlowThreshold != 0 && l.LogLevel >= Warn:
sql, rows := fc()
slowLog := fmt.Sprintf("SLOW SQL >= %v", l.SlowThreshold)
if rows == -1 {
l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceWarnStr, utils.FileWithLineNum(), slowLog, float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
case l.LogLevel == Info:
sql, rows := fc()
if rows == -1 {
l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, "-", sql, traceId, userId)
} else {
l.Printf(l.traceStr, utils.FileWithLineNum(), float64(elapsed.Nanoseconds())/1e6, rows, sql, traceId, userId)
}
}
}
}
package mysql
import (
"fmt"
_ "github.com/go-sql-driver/mysql" //加载mysql驱动
_ "github.com/joho/godotenv/autoload"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"gorm.io/gorm/schema"
"hilo-algoCenter/common/config"
"hilo-algoCenter/common/mylogrus"
"log"
"net/url"
"time"
)
var Db *gorm.DB
func init() {
var err error
mysqlConfigData := config.GetConfigMysql()
options := "?charset=utf8mb4&parseTime=True&loc=Local&time_zone=" + url.QueryEscape("'+8:00'")
dsn := "" + mysqlConfigData.MYSQL_USERNAME + ":" + mysqlConfigData.MYSQL_PASSWORD + "@(" + mysqlConfigData.MYSQL_HOST + ")/" + mysqlConfigData.MYSQL_DB + options
sqlLogger := logger.Default.LogMode(logger.Info)
if file := mylogrus.GetSqlLog(); file != nil {
//sqlLogger = logger.New(log.New(file, "\r\n", log.Ldate|log.Lmicroseconds), logger.Config{
sqlLogger = MyNew(log.New(file, "", log.Ldate|log.Lmicroseconds), logger.Config{
SlowThreshold: 200 * time.Millisecond,
LogLevel: logger.Info,
Colorful: false,
})
}
Db, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
Logger: sqlLogger,
NamingStrategy: schema.NamingStrategy{
SingularTable: true,
},
})
if err != nil {
log.Fatalf("mysql connect error %v", err)
} else {
log.Println("mysql connect success")
}
if Db.Error != nil {
fmt.Printf("database error %v", Db.Error)
}
if d, err := Db.DB(); err == nil {
d.SetConnMaxLifetime(time.Minute * 30) // 连接可复用的最大时间。
d.SetMaxIdleConns(200) // 空闲连接数
}
//移除entity的tableName
/* gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string {
return strings.Replace(defaultTableName, "_entities", "", 1)
}*/
//Db.Callback().Create().Replace("gorm:update_time_stamp", updateTimeStampForCreateCallback)
//Db.Callback().Update().Replace("gorm:update_time_stamp", updateTimeStampForUpdateCallback)
/* Db.SingularTable(true)
Db.DB().SetMaxIdleConns(10)
Db.DB().SetMaxOpenConns(100)
Db.LogMode(true)
Db.SetLogger(log.New(os.Stdout, "\r\n", 0))*/
}
/*func updateTimeStampForUpdateCallback(scope *gorm.Scope) {
if _, ok := scope.Get("gorm:update_column"); !ok {
_ = scope.SetColumn("UpdatedTime", time.Now().Unix())
}
}
func updateTimeStampForCreateCallback(scope *gorm.Scope) {
if !scope.HasError() {
nowTime := time.Now().Unix()
if createTimeField, ok := scope.FieldByName("CreatedTime"); ok {
if createTimeField.IsBlank {
_ = createTimeField.Set(nowTime)
}
}
if modifyTimeField, ok := scope.FieldByName("UpdatedTime"); ok {
if modifyTimeField.IsBlank {
_ = modifyTimeField.Set(nowTime)
}
}
}
}*/
func HasTable(tableName string) bool {
//var num int
//err := Db.Exec("SELECT COUNT(*) num FROM information_schema.TABLES WHERE table_name =%s;", tableName).Pluck("num", &num).Error
//if err != nil {
// mylogrus.MyLog.Errorf("HasTable err: %v, stack: %v", err, string(debug.Stack()))
// return
//}
//if num > 0 {
// has = true
//}
return Db.Migrator().HasTable(tableName)
}
package redisCli
import (
"context"
"github.com/go-redis/redis/v8"
"hilo-algoCenter/common/config"
"hilo-algoCenter/common/mylogrus"
"log"
)
var RedisClient *redis.Client
var RedisClient1 *redis.Client
func init() {
RedisClient = redis.NewClient(&redis.Options{
Addr: config.GetConfigRedis().REDIS_HOST,
Password: config.GetConfigRedis().REDIS_PASSWORD, // no password set
DB: 0, // use default DB
PoolSize: 2000,
MinIdleConns: 200,
})
mylogrus.MyLog.Infoln(config.GetConfigRedis().REDIS_HOST)
mylogrus.MyLog.Infoln(config.GetConfigRedis().REDIS_PASSWORD)
pong, err := RedisClient.Ping(context.Background()).Result()
if err != nil {
mylogrus.MyLog.Warn(err)
mylogrus.MyLog.Fatal("redis db0 connect fail")
} else {
mylogrus.MyLog.Info("redis db0 connection success - ", pong)
}
RedisClient1 = redis.NewClient(&redis.Options{
Addr: config.GetConfigRedis().REDIS_HOST,
Password: config.GetConfigRedis().REDIS_PASSWORD, // no password set
DB: 1, // use default DB
PoolSize: 200,
MinIdleConns: 20,
})
mylogrus.MyLog.Infoln(config.GetConfigRedis().REDIS_HOST)
mylogrus.MyLog.Infoln(config.GetConfigRedis().REDIS_PASSWORD)
pong, err = RedisClient1.Ping(context.Background()).Result()
if err != nil {
mylogrus.MyLog.Warn(err)
mylogrus.MyLog.Fatal("redis db1 connect fail")
} else {
log.Println("redis db1 connection success - " + pong)
}
// log hook
//RedisClient.AddHook(redisHook{})
}
func GetRedis() *redis.Client {
return RedisClient
}
func GetRedis1() *redis.Client {
return RedisClient1
}
package redisCli
import (
"context"
"github.com/go-redis/redis/v8"
"hilo-algoCenter/common/mylogrus"
"time"
)
type redisCost struct{}
var redisCostKey = redisCost{}
type redisHook struct{}
func (redisHook) BeforeProcess(ctx context.Context, cmd redis.Cmder) (context.Context, error) {
ctx = context.WithValue(ctx, redisCostKey, time.Now())
return ctx, nil
}
func (redisHook) AfterProcess(ctx context.Context, cmd redis.Cmder) error {
traceId, userId := ctx.Value("traceId"), ctx.Value("userId")
start := ctx.Value(redisCostKey)
var cost int64
if s, ok := start.(time.Time); ok {
cost = time.Now().Sub(s).Milliseconds()
}
mylogrus.MyLog.Infof("redis cmd: <%s>,err:%v traceId:%v,userId:%v,cost:%v ms", cmd.String(), cmd.Err(), traceId, userId, cost)
return nil
}
func (redisHook) BeforeProcessPipeline(ctx context.Context, cmds []redis.Cmder) (context.Context, error) {
return ctx, nil
}
func (redisHook) AfterProcessPipeline(ctx context.Context, cmds []redis.Cmder) error {
return nil
}
package redisCli
import (
"context"
"hilo-algoCenter/common/mylogrus"
"strconv"
"time"
)
//这个用户避免多个服务器并发问题。
func SetNX(key string, value interface{}, expiration time.Duration, callBack func()) {
flag, err := RedisClient.SetNX(context.Background(), key, value, expiration).Result()
if err != nil {
mylogrus.MyLog.Errorf("key:%v lock start setNx err: %v", key, err)
}
if !flag {
mylogrus.MyLog.Infof("key:%v lock setNx has lock", key)
return
}
mylogrus.MyLog.Infof("key:%v lock setNx begin", key)
callBack()
//执行结束之后,移除key
//RedisClient.Del(context.Background(), key)
mylogrus.MyLog.Infof("key:%v lock setNx end", key)
}
//setNx没有,结束后,没有移除
/*func SetNxNoDel(key string, value interface{}, expiration time.Duration, callBack func()) {
flag, err := RedisClient.SetNX(context.Background(), key, value, expiration).Result()
if err != nil {
mylogrus.MyLog.Errorf("key:%v lock start setNx err: %v", key, err)
}
if !flag {
mylogrus.MyLog.Infof("key:%v lock setNx has lock", key)
return
}
mylogrus.MyLog.Infof("key:%v lock setNx begin", key)
callBack()
mylogrus.MyLog.Infof("key:%v lock setNx end", key)
}*/
func ClearExpired(key string, expireSec int64) error {
return GetRedis().ZRemRangeByScore(context.Background(), key,
"0", strconv.FormatInt(time.Now().Unix()-expireSec, 10)).Err()
}
func Lock(key string, expiration time.Duration) bool {
flag, err := RedisClient.SetNX(context.Background(), key, 1, expiration).Result()
if err != nil {
return false
}
if !flag {
return false
}
return true
}
package cv
import (
"hilo-algoCenter/common/mysql"
"time"
)
// User 用户信息
type User struct {
mysql.Entity
ExternalId mysql.Str
Avatar mysql.Str
DefaultAvatar bool
Nick mysql.Str
Sex mysql.Sex
Birthday mysql.Timestamp
Country mysql.Str
CountryIcon mysql.Str
Language mysql.Str
Description mysql.Str
Code mysql.Str
OriginCode mysql.Str
IsPush mysql.OpenClose
IsShowAge mysql.OpenClose
Status mysql.Type
DeviceType mysql.Str
LogoutTime int64
}
// UserVip 用户Vip
type UserVip struct {
mysql.Entity
UserId mysql.ID
ExpireAt time.Time //结束时间
Type mysql.Type
Platform mysql.Platform
VipSubscribeOrderId mysql.ID //最后的订单ID
}
type CvUserTiny struct {
Id uint64 `json:"id,omitempty"`
ExternalId string `json:"externalId"`
Avatar string `json:"avatar"`
Nick string `json:"nick"`
Sex uint8 `json:"sex"`
Code string `json:"code"`
Country string `json:"country"`
CountryIcon string `json:"countryIcon"`
IsPrettyCode bool `json:"isPrettyCode"` // 是否靓号
IsLogout bool `json:"isLogout"` //是否注销 true:已经注销, false:没有注销
//生日,如果是其它人用户信息,年龄则按照是否展示显示,如果是本人,年龄则按照是否存在展示
Birthday *uint64 `json:"birthday"`
}
type CvUserTinyVip struct {
CvUserTiny
//是否VIP用户
IsVip bool `json:"isVip"`
//VIP用户过期时间(只有自己查询自己,才返回)
VipExpireTime *int64 `json:"vipExpireTime"`
}
func GetUserTinyVips(userIds []uint64) ([]CvUserTinyVip, error) {
userTinys, _, err := GetUserTinys(userIds)
if err != nil {
return nil, err
}
vipMap, err := BatchGetVips(userIds)
if err != nil {
return nil, err
}
userTinyVips := make([]CvUserTinyVip, 0, len(userTinys))
for i, r := range userTinys {
vipExpireTime, _ := vipMap[r.Id]
userTinyVips = append(userTinyVips, CvUserTinyVip{
CvUserTiny: userTinys[i],
IsVip: vipExpireTime != nil,
VipExpireTime: vipExpireTime,
})
}
return userTinyVips, nil
}
// GetUserTinys 批量获取用户tiny信息
func GetUserTinys(userIds []mysql.ID) ([]CvUserTiny, []uint64, error) {
if len(userIds) == 0 {
return nil, nil, nil
}
var users []User
if err := mysql.Db.Model(&User{}).Where("id IN ?", userIds).Find(&users).Error; err != nil {
return nil, nil, err
}
userTinys := make([]CvUserTiny, 0, len(users))
for _, r := range users {
userTinys = append(userTinys, GetUserTinyBy(r))
}
return userTinys, userIds, nil
}
func GetUserTinyVipMap(userIds []uint64) (map[uint64]CvUserTinyVip, error) {
userTinyVips, err := GetUserTinyVips(userIds)
if err != nil {
return nil, err
}
userTinyVipMap := map[uint64]CvUserTinyVip{}
for i, r := range userTinyVips {
userTinyVipMap[r.Id] = userTinyVips[i]
}
return userTinyVipMap, nil
}
func GetUserTinyBy(user User) CvUserTiny {
return CvUserTiny{
Id: user.ID,
Avatar: IfLogoutStr(IfLogout(user.LogoutTime), "", user.Avatar),
ExternalId: user.ExternalId,
Nick: IfLogoutNick(IfLogout(user.LogoutTime), user.Code, user.Nick),
Sex: user.Sex,
Code: user.Code,
Country: user.Country,
CountryIcon: user.CountryIcon,
IsPrettyCode: user.IsPrettyCode(),
IsLogout: IfLogout(user.LogoutTime),
Birthday: BirthdayToUint64(&user.Birthday),
}
}
func IfLogoutStr(condition bool, trueVal, falseVal string) string {
if condition {
return trueVal
}
return falseVal
}
func IfLogoutNick(condition bool, code string, nick string) string {
if condition {
return "Hilo No." + code
}
return nick
}
func IfLogout(logoutTime int64) bool {
return logoutTime > 0 && time.Now().Unix() > logoutTime
}
func BirthdayToUint64(birthday *mysql.Timestamp) *uint64 {
if *birthday == 0 {
return nil
}
return (*uint64)(birthday)
}
func (u User) IsPrettyCode() bool {
return u.Code != u.OriginCode
}
func BatchGetVips(userIds []uint64) (map[uint64]*int64, error) {
rows := make([]UserVip, 0)
err := mysql.Db.Where("user_id IN ?", userIds).Find(&rows).Error
if err != nil {
return nil, err
}
result := make(map[uint64]*int64, 0)
for _, i := range userIds {
result[i] = nil
}
now := time.Now()
for _, i := range rows {
if i.ExpireAt.After(now) {
ts := i.ExpireAt.Unix()
result[i.UserId] = &ts
}
}
return result, nil
}
package cv
import (
"hilo-algoCenter/common/mysql"
"hilo-algoCenter/protocol/userProxy"
)
type CvUserTinyVipLike struct {
CvUserTinyVip
//是否喜欢别人
IsLike bool `json:"isLike"`
//别人是否喜欢我
IsLikeMe bool `json:"isLikeMe"`
}
func GetUserTinyVipLikes(myUserId uint64, userIds []uint64) ([]CvUserTinyVipLike, error) {
if len(userIds) == 0 {
return []CvUserTinyVipLike{}, nil
}
userTinyVipMap, err := GetUserTinyVipMap(userIds)
if err != nil {
return nil, err
}
iLikeMap, err := CheckILike(myUserId, userIds)
if err != nil {
return nil, err
}
//
likeMeMap, err := CheckLikeMe(myUserId, userIds)
if err != nil {
return nil, err
}
results := make([]CvUserTinyVipLike, 0, len(userIds))
for _, r := range userIds {
results = append(results, CvUserTinyVipLike{
CvUserTinyVip: userTinyVipMap[r],
IsLike: iLikeMap[r],
IsLikeMe: likeMeMap[r],
})
}
return results, nil
}
// GetOtherUserInfo 获取otherUserId的信息
// param myUserId:用来判断喜欢/被喜欢等关系
// param otherUserId:需要获取的用户
func GetOtherUserInfo(myUserId, otherUserId uint64) (*userProxy.User, error) {
otherUser, err := GetUserTinyVipLikes(myUserId, []uint64{otherUserId})
if err != nil {
return nil, err
}
if len(otherUser) <= 0 {
return nil, err
}
otherUserInfo := otherUser[0]
var birthday uint64
if otherUserInfo.Birthday != nil {
birthday = *otherUserInfo.Birthday
}
return &userProxy.User{
Id: otherUserInfo.Id,
ExternalId: otherUserInfo.ExternalId,
Nick: otherUserInfo.Nick,
Avatar: otherUserInfo.Avatar,
Country: otherUserInfo.Country,
CountryIcon: otherUserInfo.CountryIcon,
Birthday: birthday,
IsVip: otherUserInfo.IsVip,
IsLike: otherUserInfo.IsLike,
IsLikeMe: otherUserInfo.IsLikeMe,
}, nil
}
//用户喜欢
type UserLike struct {
mysql.Entity
UserId mysql.ID
LikeUserId mysql.ID
SceneType mysql.Type
}
func CheckILike(myUserId uint64, userIds []uint64) (map[uint64]bool, error) {
var userLikes []UserLike
if err := mysql.Db.Model(&UserLike{}).Where(&UserLike{
UserId: myUserId,
}).Where("like_user_id in (?)", userIds).Find(&userLikes).Error; err != nil {
return nil, err
}
m := map[uint64]struct{}{}
for _, r := range userLikes {
m[r.LikeUserId] = struct{}{}
}
result := make(map[uint64]bool, len(userIds))
for _, r := range userIds {
_, flag := m[r]
result[r] = flag
}
return result, nil
}
func CheckLikeMe(myUserId uint64, userIds []uint64) (map[uint64]bool, error) {
var userLikes []UserLike
if err := mysql.Db.Model(&UserLike{}).Where(&UserLike{
LikeUserId: myUserId,
}).Where("user_id in (?)", userIds).Find(&userLikes).Error; err != nil {
return nil, err
}
m := map[uint64]struct{}{}
for _, r := range userLikes {
m[r.UserId] = struct{}{}
}
result := make(map[uint64]bool, len(userIds))
for _, r := range userIds {
_, flag := m[r]
result[r] = flag
}
return result, nil
}
\ No newline at end of file
[DATABASE]
MYSQL_HOST=47.244.34.27:3306
MYSQL_USERNAME=root
MYSQL_PASSWORD=yX0jPAhO0I4s2zlA
MYSQL_DB=hilo
[DATABASECODE]
MYSQL_HOST=47.244.34.27:3306
MYSQL_USERNAME=root
MYSQL_PASSWORD=yX0jPAhO0I4s2zlA
MYSQL_DB=hilo_code
[REDIS]
REDIS_HOST=47.244.34.27:6379
REDIS_PASSWORD=8QZ9JD1zLvPR3yHf
[JWT]
SECRET=hilo1632
ISSUER_API=hiloApi
ISSUER_Mgr=hiloMgr
EXPIRE=240h
[APP]
MASTER=true
BIZ_SECRET=biz
WEB_SECRET=webHilo1258
OPERATION_SECRET=operation1258236
SUPERUSER=2701,2831,4504
OFFICIAL_STAFF=2701,2831,3411,2511
OFFICIAL_GROUP=@TGS#3FDW3MPHZ
MINIMAL_VERSION_ANDROID=22001
MINIMAL_VERSION_IOS=22000
MODERATE=TENCENT
[OSS]
OSS_ACCESS_KEY_ID=LTAIxdazV2pCuV3T
OSS_ACCESS_KEY_SECRET=zuAnreAXQ6vlAKnvvmolFLfb1N5w5S
OSS_ROLE_ARN=acs:ram::1509841556585969:role/aliyunosstokengeneratorrole
OSS_END_POINT=http://oss-accelerate.aliyuncs.com
OSS_BUCKET=starvoice
OSS_CDN=https://oss.chathot.me/
OSS_EXPIRED_TIME=3600
OSS_STS_POINT=me-east-1
OSS_STS=sts-faceline-demo
OSS_STS_AES=484194d4d0f968a7
[AWS]
AWS_BUCKET=starchat
AWS_CDN=https://image.whoisamy.shop/
AWS_DIR=hilo/
CONFIDENCE=80
[RONGYUN]
RONG_CLOUD_APP_KEY=pvxdm17jpe9tr
RONG_CLOUD_APP_SECRET=rI4giiKWaBS4
RONG_CLOUD_URL=https://api-sg01.ronghub.com
[TENCENTYUN]
TENCENTYUN_APP_ID=1400548270
TENCENTYUN_KEY=321bd60f73096b059c7350f1cd97d51028850b34fa58c5c0d26bb4a19e783de8
TX_OVERSEA_APP_ID=40000066
TX_OVERSEA_KEY=3ab68ea5bddc8774d90b8c764ae71188914bd5fd06f30b28790c51e44ca7885c
[EMAS]
REGION_ID=cn-hangzhou
ACCESS_KEY_ID=LTAIdQZv5H1kNZp5
ACCESS_KEY_SECRET=UnwY0ClDkqBMLwPx3OJJiLYyk9xYLO
ANDROID_APP_KEY=30250713
ANDROID_APP_SECRET=cae7b9a9d3e54577d2c3b60bf6d23047
IOS_APP_KEY=30790728
IOS_APP_SECRET=4fd69ca084c67d4b5a8d15452f0af26a
APNS=DEV
[AGORA]
APP_ID=fc3e087f701b4f788099e1924c3cc7b0
APP_CERTIFICATE=ff29c100a613433db82324e8411eabc8
CUSTOMER_KEY=6b132c0ff7164560a2bc53fda06ea85a
CUSTOMER_SECRET=eedad2cd16d24834990d5450ace9f1ce
CALLBACK_SECRET=n_ZizS_N8
[CHECKOUT]
AUTHORIZATION=sk_test_9b5e771c-5a3f-4a8d-a4da-31b19bd43d83
URL=https://api.sandbox.checkout.com/hosted-payments
H5=https://test.chathot.me/action/hiloHtml/22_05_30_recharge/topup.html
HILO_SECRET_KEY=sk_test_dfbaa3b6-135d-4376-9996-2089b7d8a086
[MATCH]
MATCH_FREE_TIME=60
MATCH_FREE_TIME_VIP=60
MATCH_ADD_TIME_FREE=90
MATCH_AGORA_TIME=30
MATCH_CYCLE=8
MATCH_USER_EXPIRES=480
MATCH_SUCCESS_WAIT_DURATION=10
MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC=12
MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC=15
[ONLINE]
ONLINE_CYCLE=600
ONLINE_USER_EXPIRES=259200
[VIDEO]
VIDEO_DAILY_FREE_NUM=20
VIDEO_FREE_TIME=60
VIDEO_FREE_TIME_VIP=300
VIDEO_ADD_TIME_FREE=60
VIDEO_AGORA_TIME=30
VIDEO_MINUTE_NORMAL=30
VIDEO_MINUTE_UNION=30
[SESSION]
SESSION_DAILY_FREE_NUM=50
GUILD_USER_HELLO_DAY=30
[BEAN]
DIAMOND_BEAN_RATE=90
[GEM]
DIAMOND_GEM_RATE=10
[H5]
USER_LEVEL=http://test.chathot.me/action/hiloHtml/hiloUserLevel/index.html
GROUP_SUPPORT=http://test.chathot.me/action/activityhtml/21_12_06/page.html
LUCKY_WHEEL=https://test.chathot.me/action/activityhtml/21_12_30/page.html
WEEKLY_STAR=http://test.chathot.me/action/hiloHtml/lxt_h5/page.html
WEEKLY_CP=https://test.chathot.me/action/hiloHtml/Valentines_22_1_18/page.html
COUNTRY_STAR=https://test.chathot.me/action/hiloHtml/22_08_18_nation_star/page.html
NOBLE_BUY_IOS=https://test.chathot.me/action/hiloHtml/22_05_26_buy_nobility/page.html
NOBLE_BUY_IOS_AUDIT=https://test.chathot.me/action/hiloHtml/lxt_h5/page.html
GUILD_DATA_URL=https://test.chathot.me/action/hiloHtml/22_10_18_app_data_coins/index.html
MGR_GUILD_DATA_URL=https://test.chathot.me/action/hiloHtml/22_10_18_app_data_coins/union.html
RANKING_PINK_DIAMOND_URL=https://test.chathot.me/action/activitiesPage/2022_10_17HiloLiveH5/index.html
GROUP_POWER_GRADE_URL=https://test.chathot.me/action/hiloHtml/2023Activity/2023_3_21FamilyLevel/index.html
GROUP_POWER_ACT_URL=
SHEEP_H5_URL=https://gzds.vip/yangyang?game_id=hilo_sheep
ID_URL=https://h5.whoisamy.shop/action/hiloHtml/new_upgrade/index.html
[GROUPIM]
MSG_SORT_EXPIRE=21600
MSG_SORT_SNAP=300
MSG_PARALLEL_SIZE=10
[GRADE]
CHARM_SPEED_VIP=15
ACTITY_SPEED_VIP=15
WEALTH_SPEED_VIP=15
[LIKE]
I_LIKE_NUM=30
I_LIKE_NUM_VIP=300
I_LIKE_NUM_NOBLE=1000
[APPLEPAY]
PASSWORD=38702750a05c4cb09c9d6ca646835634
[REGISTER]
IMEI_TOTAL=3
IMEI_OAUTH=2
ACCOUNT_IP=100
ACCOUNT_IP_DURATION=21600
[BANNER]
GIFT_BANNER_LEVEL1=500
GIFT_BANNER_LEVEL2=2000
GIFT_BANNER_LEVEL3=5000
[DIAMOND]
DAILY_LOGIN_IMEI_LIMIT=2
DAILY_LOGIN_IP_LIMIT=5
PRIVATE_GIFT_RETURN=10
[LUCKY_WHEEL]
MINIMAL_PARTICIPANT=2
WAIT_TIMELONG=10
WINNER_DIAMOND_BANNER=10
[GROUP_CUSTOM_THEME]
PIC_LIMIT=5
DAY=10
[GIFT]
WALL_DIAMOND=10
[DAILY]
LOGIN_COMMON=5
LOGIN_VIP=300
[FRUIT_TYCOON]
POOL_RATIO=80
WATERMELON_RATIO=24
[RISK_CONTROL]
USER_QPS_LIMIT=60
[PAYER_MAX]
URL=https://pay-gate-uat.payermax.com/aggregate-pay-gate/api/gateway
KEY=d50d149a883b8bb6
MERCHANT_ID=SP11018326
BIZ_TYPE=CUSTOMIZE
VERSION=2.3
FRONT_CALLBACK_URL=https://www.hiloconn.com
SHOW_RESULT=1
EXPIRE_TIME=1800
LANGUAGE=en
[PAYPAL]
PAYPAL_CLIENT_ID=AQCXHyXFhNLNWoorcj3Du0J4WwBDy25DoQ7SZKNKRe4PNY0BLpeCzV_zm1HKwAvd7reWeOBCte-vMakM
PAYPAL_SECRET_ID=EDBTK99v6wXhGXhDqDTOksK2j8NPAfJKT-wRTqTrNGrUmn8xsjkrVcO_xSvMVR6CB2bN74rGl_AFm098
RETURN_URL=https://test.apiv1.faceline.live/v1/callback/paypal
\ No newline at end of file
module hilo-algoCenter
go 1.17
require (
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da // indirect
github.com/cespare/xxhash/v2 v2.1.1 // indirect
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
github.com/fatih/color v1.9.0 // indirect
github.com/go-redis/redis/v8 v8.3.3 // indirect
github.com/go-sql-driver/mysql v1.5.0 // indirect
github.com/golang/protobuf v1.4.3 // indirect
github.com/hashicorp/consul/api v1.7.0 // indirect
github.com/hashicorp/go-cleanhttp v0.5.1 // indirect
github.com/hashicorp/go-hclog v0.12.0 // indirect
github.com/hashicorp/go-immutable-radix v1.0.0 // indirect
github.com/hashicorp/go-rootcerts v1.0.2 // indirect
github.com/hashicorp/golang-lru v0.5.0 // indirect
github.com/hashicorp/serf v0.9.3 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.1 // indirect
github.com/joho/godotenv v1.3.0 // indirect
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible // indirect
github.com/lestrrat-go/strftime v1.0.6 // indirect
github.com/mattn/go-colorable v0.1.6 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.1.2 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 // indirect
github.com/satori/go.uuid v1.2.0 // indirect
github.com/sirupsen/logrus v1.7.0 // indirect
go.opentelemetry.io/otel v0.13.0 // indirect
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 // indirect
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f // indirect
golang.org/x/text v0.3.3 // indirect
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
google.golang.org/grpc v1.42.0 // indirect
google.golang.org/protobuf v1.25.0 // indirect
gopkg.in/ini.v1 v1.63.2 // indirect
gorm.io/driver/mysql v1.0.3 // indirect
gorm.io/gorm v1.20.12 // indirect
)
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da h1:8GUt8eRujhVEGZFFEjBj46YV4rDjvGrNxb0KMWYkL2I=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-redis/redis/v8 v8.3.3 h1:e0CL9fsFDK92pkIJH2XAeS/NwO2VuIOAoJvI6yktZFk=
github.com/go-redis/redis/v8 v8.3.3/go.mod h1:jszGxBCez8QA1HWSmQxJO9Y82kNibbUmeYhKWrBejTU=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.7.0 h1:tGs8Oep67r8CcA2Ycmb/8BLBcJ70St44mF2X10a/qPg=
github.com/hashicorp/consul/api v1.7.0/go.mod h1:1NSuaUUkFaJzMasbfq/11wKYWSR67Xn6r2DXKhuDNFg=
github.com/hashicorp/consul/sdk v0.6.0/go.mod h1:fY08Y9z5SvJqevyZNy6WWPXiG3KwBPAvlcdx16zZ0fM=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-hclog v0.12.0 h1:d4QkX8FRTYaKaCZBoXYY8zJX2BXjWxurN/GA2tkrmZM=
github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
github.com/hashicorp/go-immutable-radix v1.0.0 h1:AKDB1HM5PWEA7i4nhcpwOrO2byshxBjXVn/J/3+z5/0=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
github.com/hashicorp/go-rootcerts v1.0.2 h1:jzhAVGtqPKbwpyCPELlgNWhE1znq+qwJtW5Oi2viEzc=
github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY=
github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE=
github.com/hashicorp/serf v0.9.3 h1:AVF6JDQQens6nMHT9OGERBvK0f8rPrAGILnsKLr6lzM=
github.com/hashicorp/serf v0.9.3/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.1 h1:g39TucaRWyV3dwDO++eEc6qf8TVIQ/Da48WmqjZ3i7E=
github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4=
github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible/go.mod h1:ZQnN8lSECaebrkQytbHj4xNgtg8CR7RYXnPok8e0EHA=
github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ=
github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.2/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/onsi/gomega v1.10.3/go.mod h1:V9xEwhxec5O8UDM77eCW8vLymOMltsqPVYWrpDsH8xc=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnHyvtYjDeq0zlVHn9K/ZXoy17ylucdo=
github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0 h1:wBouT66WTYFXdxfVdz9sVWARVd/2vfGcmI45D2gj45M=
golang.org/x/net v0.0.0-20201006153459-a7d1128ccaa0/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200124204421-9fbb57f87de9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f h1:+Nyd8tzPX9R7BWHguqsrbFdRx3WQ/1ib8I44HXV5yTA=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190907020128-2ca718005c18/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.42.0 h1:XT2/MFpuPFsEX2fWh3YQtHkZ+WYZFQRfaUgLZYj/p6A=
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gorm.io/driver/mysql v1.0.3 h1:+JKBYPfn1tygR1/of/Fh2T8iwuVwzt+PEJmKaXzMQXg=
gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.20.12 h1:ebZ5KrSHzet+sqOCVdH9mTjW91L298nX3v5lVxAzSUY=
gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
[DATABASE]
MYSQL_HOST=47.244.34.27:3306
MYSQL_USERNAME=root
MYSQL_PASSWORD=yX0jPAhO0I4s2zlA
MYSQL_DB=hilo
[DATABASECODE]
MYSQL_HOST=47.244.34.27:3306
MYSQL_USERNAME=root
MYSQL_PASSWORD=yX0jPAhO0I4s2zlA
MYSQL_DB=hilo_code
[REDIS]
REDIS_HOST=47.244.34.27:6379
REDIS_PASSWORD=8QZ9JD1zLvPR3yHf
[JWT]
SECRET=hilo1632
ISSUER_API=hiloApi
ISSUER_Mgr=hiloMgr
EXPIRE=240h
[APP]
MASTER=false
BIZ_SECRET=biz
WEB_SECRET=webHilo1258
OPERATION_SECRET=operation1258236
SUPERUSER=2701,2831
OFFICIAL_STAFF=2701,2831
OFFICIAL_GROUP=@TGS#3NC2ATRHS,@TGS#33W3KNLHK
MINIMAL_VERSION_ANDROID=212
MINIMAL_VERSION_IOS=100
MODERATE=AWS
[OSS]
OSS_ACCESS_KEY_ID=LTAIxdazV2pCuV3T
OSS_ACCESS_KEY_SECRET=zuAnreAXQ6vlAKnvvmolFLfb1N5w5S
OSS_ROLE_ARN=acs:ram::1509841556585969:role/aliyunosstokengeneratorrole
OSS_END_POINT=http://oss-accelerate.aliyuncs.com
OSS_BUCKET=starvoice
OSS_CDN=https://oss.chathot.me/
OSS_EXPIRED_TIME=3600
OSS_STS_POINT=me-east-1
OSS_STS=sts-faceline-demo
OSS_STS_AES=484194d4d0f968a7
[AWS]
AWS_BUCKET=starchat
AWS_CDN=https://image.whoisamy.shop/
AWS_DIR=hilo/
CONFIDENCE=80
[RONGYUN]
RONG_CLOUD_APP_KEY=pvxdm17jpe9tr
RONG_CLOUD_APP_SECRET=rI4giiKWaBS4
RONG_CLOUD_URL=https://api-sg01.ronghub.com
[TENCENTYUN]
TENCENTYUN_APP_ID=1400548270
TENCENTYUN_KEY=321bd60f73096b059c7350f1cd97d51028850b34fa58c5c0d26bb4a19e783de8
TX_OVERSEA_APP_ID=40000066
TX_OVERSEA_KEY=3ab68ea5bddc8774d90b8c764ae71188914bd5fd06f30b28790c51e44ca7885c
[EMAS]
REGION_ID=cn-hangzhou
ACCESS_KEY_ID=LTAI4FhNPzxdzD4w6bHirL9Z
ACCESS_KEY_SECRET=OQvUJpXDrjGi3g1F2aHiAIFWIvLdbP
ANDROID_APP_KEY=30250713
ANDROID_APP_SECRET=cae7b9a9d3e54577d2c3b60bf6d23047
IOS_APP_KEY=30240346
IOS_APP_SECRET=57f33ab9ca6a957a8c659f2b0b6d1205
APNS=DEV
[AGORA]
APP_ID=fc3e087f701b4f788099e1924c3cc7b0
APP_CERTIFICATE=ff29c100a613433db82324e8411eabc8
CUSTOMER_KEY=6b132c0ff7164560a2bc53fda06ea85a
CUSTOMER_SECRET=eedad2cd16d24834990d5450ace9f1ce
CALLBACK_SECRET=n_ZizS_N8
[CHECKOUT]
AUTHORIZATION=sk_test_9b5e771c-5a3f-4a8d-a4da-31b19bd43d83
URL=https://api.sandbox.checkout.com/hosted-payments
H5=http://test.chathot.me/action/hiloHtml/22_05_30_recharge/topup.html
HILO_SECRET_KEY=sk_test_dfbaa3b6-135d-4376-9996-2089b7d8a086
[MATCH]
MATCH_FREE_TIME=60
MATCH_FREE_TIME_VIP=300
MATCH_ADD_TIME_FREE=90
MATCH_AGORA_TIME=30
MATCH_CYCLE=8
MATCH_USER_EXPIRES=480
MATCH_SUCCESS_WAIT_DURATION=10
MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC=12
MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC=15
[ONLINE]
ONLINE_CYCLE=600
ONLINE_USER_EXPIRES=259200
[VIDEO]
VIDEO_DAILY_FREE_NUM=20
VIDEO_FREE_TIME=60
VIDEO_FREE_TIME_VIP=300
VIDEO_ADD_TIME_FREE=60
VIDEO_AGORA_TIME=30
VIDEO_MINUTE_NORMAL=1000
VIDEO_MINUTE_UNION=2000
[SESSION]
SESSION_DAILY_FREE_NUM=50
[BEAN]
DIAMOND_BEAN_RATE=90
[GEM]
DIAMOND_GEM_RATE=10
[H5]
USER_LEVEL=http://test.chathot.me/action/activityhtml/hiloUserLevel/index.html
GROUP_SUPPORT=http://test.chathot.me/action/activityhtml/21_12_06/page.html
LUCKY_WHEEL=https://h5.whoisamy.shop/action/activityhtml/21_12_30/page.html
NOBLE_BUY_IOS=https://h5.whoisamy.shop/action/hiloHtml/lxt_h5/page.html
NOBLE_BUY_IOS_AUDIT=https://h5.whoisamy.shop/action/hiloHtml/lxt_h5/page.html
GROUP_POWER_GRADE_URL=https://test.chathot.me/action/hiloHtml/2023Activity/2023_3_21FamilyLevel/index.html
GROUP_POWER_ACT_URL=https://www.baidu.com
SHEEP_H5_URL=https://gzds.vip/yangyang?game_id=hilo_sheep
ID_URL=https://h5.whoisamy.shop/action/hiloHtml/new_upgrade/index.html
[GROUPIM]
MSG_SORT_EXPIRE=43200
MSG_SORT_SNAP=300
[GRADE]
CHARM_SPEED_VIP=15
ACTITY_SPEED_VIP=15
WEALTH_SPEED_VIP=15
[LIKE]
I_LIKE_NUM=30
I_LIKE_NUM_VIP=100
I_LIKE_NUM_NOBLE=1000
[APPLEPAY]
PASSWORD=38702750a05c4cb09c9d6ca646835634
[REGISTER]
IMEI_TOTAL=3
IMEI_OAUTH=2
ACCOUNT_IP=100
ACCOUNT_IP_DURATION=21600
[BANNER]
GIFT_BANNER_LEVEL1=100
GIFT_BANNER_LEVEL2=2000
GIFT_BANNER_LEVEL3=5000
[DIAMOND]
DAILY_LOGIN_IMEI_LIMIT=200
DAILY_LOGIN_IP_LIMIT=5
PRIVATE_GIFT_RETURN=1440
NEW_USER_INVITE_AWARD=5000
[LUCKY_WHEEL]
MINIMAL_PARTICIPANT=2
WAIT_TIMELONG=10
WINNER_DIAMOND_BANNER=100
[GROUP_CUSTOM_THEME]
PIC_LIMIT=5
DAY=10
[GIFT]
WALL_DIAMOND=10
[DAILY]
LOGIN_COMMON=5
LOGIN_VIP=300
[DAILY]
LOGIN_COMMON=5
LOGIN_VIP=300
[FRUIT_TYCOON]
POOL_RATIO=20
WATERMELON_RATIO=70
[ACTIVITY]
COUNTRY_STAR_POOL_RATIO=20
COUNTRY_STAR_ORDINARY_RATIO=20
[PAYER_MAX]
URL=https://pay-gate-uat.payermax.com/aggregate-pay-gate/api/gateway
KEY=d50d149a883b8bb6
MERCHANT_ID=SP11018326
BIZ_TYPE=CUSTOMIZE
VERSION=2.3
FRONT_CALLBACK_URL=https://www.hiloconn.com
SHOW_RESULT=1
EXPIRE_TIME=1800
LANGUAGE=en
\ No newline at end of file
package main
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
consulapi "github.com/hashicorp/consul/api"
"google.golang.org/grpc"
"google.golang.org/grpc/keepalive"
"google.golang.org/grpc/resolver"
"google.golang.org/grpc/resolver/manual"
"hilo-algoCenter/algo"
"hilo-algoCenter/common/consul"
"hilo-algoCenter/common/mylogrus"
"hilo-algoCenter/protocol/userCenter"
"time"
)
const (
default_redis_address = "47.244.34.27:6379"
default_redis_password = "8QZ9JD1zLvPR3yHf"
redis_section = 0
)
var kacp = keepalive.ClientParameters{
Time: 10 * time.Second, // send pings every 10 seconds if there is no activity
Timeout: time.Second, // wait 1 second for ping ack before considering the connection dead
PermitWithoutStream: true, // send pings even without active streams
}
func main() {
client, err := consulapi.NewClient(consulapi.DefaultConfig()) //非默认情况下需要设置实际的参数
if err != nil {
mylogrus.MyLog.Fatalln(err)
}
if client == nil {
mylogrus.MyLog.Fatalln("Fail to get consul client.")
}
redisAddress := default_redis_address
redisPassword := default_redis_password
kv := client.KV()
if kv != nil {
p, _, err := kv.Get("redis_address", nil)
if err == nil && p != nil {
redisAddress = string(p.Value)
}
p, _, err = kv.Get("redis_password", nil)
if err == nil && p != nil {
redisPassword = string(p.Value)
}
}
rdb := redis.NewClient(&redis.Options{
Addr: redisAddress,
Password: redisPassword,
DB: redis_section,
})
if rdb == nil {
mylogrus.MyLog.Fatalf("failed to connect redis %s\n", redisAddress)
}
result, err := rdb.Ping(context.Background()).Result()
if err != nil {
mylogrus.MyLog.Fatal(err)
} else if result != "PONG" {
mylogrus.MyLog.Fatalf("Invalid ping response %s", result)
}
cataLog := client.Catalog()
if cataLog == nil {
mylogrus.MyLog.Fatalln("No catalog.")
}
addr, err := consul.GetServices(cataLog, "userCenter")
if err != nil {
mylogrus.MyLog.Fatalln(err)
}
if len(addr) == 0 {
mylogrus.MyLog.Fatalln("No userCenter available.")
}
addresses := make([]resolver.Address, len(addr))
for i, s := range addr {
addresses[i].Addr = s
mylogrus.MyLog.Infof("address : %s", s)
}
r := manual.NewBuilderWithScheme("hilo")
r.InitialState(resolver.State{Addresses: addresses})
userCenterAddr := fmt.Sprintf("%s:///usercenter", r.Scheme())
// Set up addresses connection to the userCenter.
conn, err := grpc.Dial(userCenterAddr,
grpc.WithInsecure(),
grpc.WithBlock(),
grpc.WithKeepaliveParams(kacp),
grpc.WithResolvers(r),
grpc.WithDefaultServiceConfig("{ \"loadBalancingPolicy\": \"round_robin\" }"))
if err != nil {
mylogrus.MyLog.Fatalf("did not connect: %v", err)
}
//defer conn.Close()
userClient := userCenter.NewUserClient(conn)
if userClient == nil {
mylogrus.MyLog.Fatalln("userClient null")
}
algo.Start(userClient, rdb)
select {}
}
package protocol
const MatchResultPubSubChannel = "match_result"
type MatchResult struct {
MatchCycle string `json:"matchCycle"`
MatchUniqueId string `json:"matchUniqueId"`
//Total uint32 `json:"total"`
User1Id uint64 `json:"user1Id"`
User2Id uint64 `json:"user2Id"`
//true:正常匹配 false:落单
Status bool `json:"status"`
//1, 是正常结果,2:只有一个用户,发起工会广播
//Type uint32 `json:"type"`
//user1Id的优先度分数
Priority float64
//user2Id的质量分数
Excellen float64
//user1Id同user2Id的关系分数
Relation float64
ExcellentRelation float64
//rpc状态
RpcStatus bool
//rpc错误信息
RPcErr string
}
const MatchCyclePubSubChannel = "match_cycle"
//匹配周期结果
type MatchCycle struct {
//周期
MatchCycle string `json:"matchCycle"`
//参与匹配的人数
JoinNum uint32 `json:"joinNum"`
//匹配成功的人数
SuccessNum uint32 `json:"successNum"`
//匹配失败的人数
FailNum uint32 `json:"failNum"`
//是否发出工会广播 1:广播 2:不广播
TradeUnionBroadcast uint8 `json:"tradeUnionBroadcast"`
}
syntax = "proto3";
package userCenter;
option go_package = "protocol/userCenter";
/* id = 1 */
message RouteMessage {
uint64 uid = 1;
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 2 */
message RouteMessageRsp {
uint32 status = 1;
}
/* id = 3 */
message LoginMessage {
string proxyAddr = 1; // userProxy的地址:ip:port
string token = 2;
string clientAddr = 3; // 客户端地址(websocket):ip:port
}
/* id = 4 */
message LoginMessageRsp {
uint32 status = 1;
uint64 uid = 2;
}
/* id = 5 */
message LogoutMessage {
string clientAddr = 1; // 客户端地址(websocket):ip:port
uint64 uid = 2;
}
/* id = 6 */
message LogoutMessageRsp {
uint32 status = 1;
}
/* id = 7 */
message MulticastMessage {
repeated uint64 uids = 1;
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 8 */
message MulticastMessageRsp {
repeated uint64 failedUids = 1;
}
/* id = 9 */
message KickMessage {
uint64 uid = 1;
string addr = 2;
}
/* id = 10 */
message KickMessageRsp {
uint32 status = 1;
}
/* id = 11 */
message BroadcastMessage {
uint32 msgType = 2;
bytes payLoad = 3;
}
/* id = 12 */
message BroadcastMessageRsp {
repeated uint64 failedUids = 1;
}
/* id = 13 */
message BizMessage {
uint64 uid = 1;
uint32 msgType = 2;
string payLoad = 3;
}
/* id = 14 */
message BizMessageRsp {
uint32 status = 1;
}
service Router {
rpc route(RouteMessage) returns (RouteMessageRsp) {}
rpc kickUser(KickMessage) returns (KickMessageRsp) {}
}
service User {
rpc login(LoginMessage) returns (LoginMessageRsp) {}
rpc logout(LogoutMessage) returns (LogoutMessageRsp) {}
rpc multicast(MulticastMessage) returns (MulticastMessageRsp) {}
rpc broadcast(BroadcastMessage) returns (BroadcastMessageRsp) {}
rpc transmit(BizMessage) returns (BizMessageRsp) {}
}
\ No newline at end of file
syntax = "proto3";
package userProxy;
option go_package = "protocol/userProxy";
/* user*/
message User {
uint64 id = 1;
string externalId = 2;
string nick = 3;
string avatar = 4;
string country = 5;
string countryIcon = 6;
uint64 birthday = 7;
bool isVip = 8;
bool isLike = 9;
bool isLikeMe = 10;
}
/* Svip*/
message Svip {
uint64 svipLevel = 1;
repeated SvipPrivilege privileges = 2;
}
message SvipPrivilege {
int32 type = 1;
bool canSwitch = 2;
bool userSwitch = 3;
string mysteryCode = 4;
}
/* id = 1 登录*/
message Login {
string token = 1;
}
/* id = 2 登录的回应 */
message LoginRsp {
uint32 status = 1;
}
/* id = 3 客户端心跳 */
message HeartBeat {
string externalUid = 1;
}
/* id = 4 客户端心跳的回应 */
message HeartBeatRsp {
uint32 status = 1;
}
/* id = 7 客户端上行消息 */
message BizRequest {
uint32 type = 1;
string payLoad = 2;
}
/* id = 8 客户端上行消息的应答 */
message BizResponse {
uint32 status = 1;
}
/* id == 100 | 140 匹配结果通知 waitDuration:开始/下一个时间 matchUniqueId:匹配一对的唯一标识码, status:是否是落单 singleWaitTimeInSec:单方等待连接最长时间 dualWaitTimeInSec:双方连接中最长时间*/
message MatchSuccess {
string localUserId = 1;
string remoteUserId = 2;
uint32 waitDuration = 3;
string matchUniqueId = 4;
bool status = 5;
uint32 singleWaitTimeInSec = 6;
uint32 dualWaitTimeInSec = 7;
User remoteUser = 8;
}
/* id == 101 匹配后用户选择结果通知, failType: 只有status=2 才有值,其它为0,failType=1:等待时间到了,拒绝 failType=2:主动拒绝 */
message MatchConfirm {
uint32 status = 1;
string channelId = 2;
string token = 3;
string localUserId = 4;
string remoteUserId = 5;
uint32 remoteAgoraId = 6;
uint32 callDuration = 7;
uint32 localAgoraId = 8;
uint32 diamondBalance = 9;
string matchUniqueId = 10;
uint32 failType = 11;
}
/* id == 102 视频通话准备 */
message CallReady {
uint64 startTimestamp = 1;
uint64 endTimestamp = 2;
uint64 callDuration = 3;
string channelId = 4;
uint64 remainDiamond = 5;
}
/* id == 103 礼物加时 */
message AddTimeGift {
uint32 giftId = 1;
string token = 2;
uint32 duration = 3;
uint64 endTimestamp = 4;
string channelId = 5;
bool isSender = 6;
uint32 giftNum = 7;
string iconUrl = 8;
string svgaUrl = 9;
string senderAvatar = 10;
string receiverAvatar = 11;
}
/* id == 104 免费加时 */
message AddTimeFree {
string token = 1;
uint32 duration = 2;
uint64 endTimestamp = 3;
string channelId = 4;
uint32 senderAgoraId = 5;
}
/* id == 105 退出 */
message ConnectsQuit {
uint64 from_user_id = 1;
}
/* id == 106 连接状态 */
message ConnectStatus {
uint64 from_user_id = 1;
float user_diamonds = 2;
bool diamonds_enough = 3;
}
/* id == 107 ??? */
message ConnectsCall {
uint64 from_user_id = 1;
string rong_room_name = 2;
bool is_join = 3;
}
/* id == 108 */
message ConnectCommon {
string rong_room_name = 1;
uint64 from_user_id = 2;
string extra = 3;
string message = 4;
}
/* id == 109 召回授权弹框 */
message RecallWindow {
}
/* id == 110 | 132 视频发送 status:(1:接收到邀请, 2:接收到对方同意, 3:双方拒绝(还没接通), 4:对方挂断(接通后)diamondBalance 只有status=2,才出现)*/
message Video {
string videoUniqueId = 1;
string channelId = 2;
uint32 localAgoraId = 3;
uint32 remoteAgoraId = 4;
string agoraToken = 5;
string sendUserId = 6;
string receiveUserId = 7;
uint32 status = 8;
uint32 diamondBalance = 9;
User sendUser = 10;
}
/* id == 111 视频通话准备 */
message VideoCallReady {
uint64 startTimestamp = 1;
uint64 endTimestamp = 2;
uint64 callDuration = 3;
string channelId = 4;
uint64 remainDiamond = 5;
}
/* id == 112 互相喜欢 */
message LikeEach {
string remoteUserId = 1;
}
/* id == 113 喜欢我 */
message LikeMe {
string remoteUserId = 1;
string remoteNick = 2;
string channelId = 3;
}
/* id == 114 日常进入app,获取钻石 */
message DailyInAppDiamond {
uint32 diamondNum = 1;
}
/* id == 115 横幅 */
message GlobalGiftBanner {
uint32 bannerLevel = 1;
uint64 giftId = 2;
uint32 giftNum = 3;
string sendUserId = 4;
string receiveUserId = 5;
string groupId = 6;
string sendUserCode = 7;
string sendUserAvatar = 8;
string sendUserNick = 9;
string receiveUserNick = 10;
string giftPicUrl = 11;
Svip svip = 12;
Svip receiveSvip = 13;
}
/* id == 116 横幅的回应,用来测量RTT */
message GlobalGiftBannerRsp {
uint32 bannerLevel = 1;
uint64 giftId = 2;
uint32 giftNum = 3;
string sendUserId = 4;
string receiveUserId = 5;
string groupId = 6;
}
/*id==117 幸运转盘通知,客户端重新拉取查询, type:客户端不用理*/
message LuckyWheel {
string groupId = 1;
uint32 type = 2;
}
/* id == 118 幸运转盘获胜者全服广播 */
message LuckyWheelBanner {
uint32 diamondNum = 1;
string sendUserId = 2;
string groupId = 3;
string nick = 4;
string code = 5;
string avatar = 6;
Svip svip = 7;
}
/* id == 119 幸运转盘钻石变化 */
message LuckyWheelDiamondChange {
string groupId = 1;
}
/* id == 120 服务器配置变更 */
message ConfigChange {
uint32 type = 1;
}
/* id == 121 全局火箭横幅 */
message GlobalRocketNotice {
string groupId = 1;
string period = 2;
uint32 round = 3;
uint32 stage = 4;
string topUserIcon = 5;
string nick = 6;
string code = 7;
string avatar = 8;
Svip svip = 9;
}
/* id == 122 群发功能弹窗 */
message GroupSendNotice {
string senderExtId = 1;
string senderCode = 2;
uint32 senderSex = 3;
string senderAvatar = 4;
string text = 5;
string groupName = 6;
string groupCode = 7;
string groupAvatar = 8;
uint32 userInNum = 9; // 最近进入房间的人数
string groupId = 10;
}
/* id == 123 全球消息 */
message GlobalBroadcast {
string senderExtId = 1;
string senderCode = 2;
uint32 senderSex = 3;
string senderAvatar = 4;
string senderNick = 5;
string msg = 6;
string groupId = 7;
uint32 senderNobleLevel = 8;
}
/* id == 124 全球消息 */
message MicTaskFinish {
string userId = 1;
uint32 diamond = 2;
}
/* id == 125 水果机开奖通知 */
message FruitMachine {
string date = 1;
uint32 round = 2;
}
/* id == 126 贵族变化 */
message NobleChange {
}
/* id == 127 加入群组成功 */
message JoinGroup {
string groupId = 1;
string externalId = 2;
}
/* id == 128 1对1视频1分钟加时成功 */
message VideoTimeMinuteSuccess {
string token = 1;
uint32 duration = 2;
uint64 endTimestamp = 3;
string channelId = 4;
uint32 senderAgoraId = 5;
string videoUniqueId = 6;
bool isSend = 7;
uint32 sendRemainDiamond = 8;
}
/* id == 129 1对1视频1分钟加时询问检查 */
message VideoTimeMinuteCheck {
string videoUniqueId = 1;
uint32 diamond = 2;
string uuid = 3;
}
/* id == 130 1对1视频,错过 */
message VideoMiss {
uint32 totalNum = 1;
}
/* id == 131 进房,群组活动信息 */
message GroupActivity {
string ActivityId = 1;// id
uint64 StartAt = 2; // 开始时间戳,东八区时间戳
uint64 EndAt = 3; // 结束时间戳,东八区时间戳
string Banner = 4; // banner url
int32 AcType = 5; // 类型1.游戏2.比赛3.排队4.诗歌
string Theme = 6; // 活动主题
int32 PersonNum = 7; // 订阅人数
bool IsSubscribe = 8; // 我是否订阅该活动
string GroupId = 9; // 群id
}
/* id == 144 邀请用户成为房间会员 */
message RoomInviteMember {
string group_id = 1;
}
\ No newline at end of file
[DATABASE]
MYSQL_HOST=ua4papc3hmgqf351pbej-rw4rm.rwlb.dubai.rds.aliyuncs.com
MYSQL_USERNAME=nextvideo
MYSQL_PASSWORD=ihlUwI4nhi9W88MI
MYSQL_DB=hilo
[DATABASECODE]
MYSQL_HOST=ua4papc3hmgqf351pbej-rw4rm.rwlb.dubai.rds.aliyuncs.com
MYSQL_USERNAME=nextvideo
MYSQL_PASSWORD=ihlUwI4nhi9W88MI
MYSQL_DB=hilo_code
[REDIS]
REDIS_HOST=r-eb3btxn8vfdsuwdbuf.redis.dubai.rds.aliyuncs.com:6379
REDIS_PASSWORD=
[JWT]
SECRET=hilo1504
ISSUER_API=hiloApi
ISSUER_Mgr=hiloMgr
EXPIRE=720h
[APP]
MASTER=true
BIZ_SECRET=biz
OPERATION_SECRET=operation1258236
WEB_SECRET=webHilo1258
SUPERUSER=28201,23951,133101,41,2020531,955271,1575531
OFFICIAL_STAFF=133101,435731,486461,41
OFFICIAL_GROUP=@TGS#33W3KNLHK,@TGS#3XA5RJ5HH,@TGS#3O6PKBTH6
MINIMAL_VERSION_ANDROID=22600
MINIMAL_VERSION_IOS=22600
ROOM_MODE=AVChatRoom
MODERATE=TENCENT
[OSS]
OSS_ACCESS_KEY_ID=LTAIxdazV2pCuV3T
OSS_ACCESS_KEY_SECRET=zuAnreAXQ6vlAKnvvmolFLfb1N5w5S
OSS_ROLE_ARN=acs:ram::1509841556585969:role/aliyunosstokengeneratorrole
OSS_END_POINT=https://oss-accelerate.aliyuncs.com
OSS_BUCKET=starvoice
OSS_CDN=https://oss.chathot.me/
OSS_EXPIRED_TIME=3600
OSS_STS_POINT=me-east-1
OSS_STS=sts-faceline-demo
OSS_STS_AES=484194d4d0f968a7
[AWS]
AWS_BUCKET=starchat
AWS_CDN=https://image.whoisamy.shop/
AWS_DIR=hilo/
CONFIDENCE=80
[RONGYUN]
RONG_CLOUD_APP_KEY=uwd1c0sxu5t41
RONG_CLOUD_APP_SECRET=vo9djozyBl9bZ
RONG_CLOUD_URL=https://api-sg01.ronghub.com
[TENCENTYUN]
TENCENTYUN_APP_ID=1400487464
TENCENTYUN_KEY=cb4c1f2e3398a88e0e9468b403f671e60d66a564df86f7db925c6ab4f18b66e5
TX_OVERSEA_APP_ID=40000066
TX_OVERSEA_KEY=3ab68ea5bddc8774d90b8c764ae71188914bd5fd06f30b28790c51e44ca7885c
[EMAS]
REGION_ID=cn-hangzhou
ACCESS_KEY_ID=LTAIdQZv5H1kNZp5
ACCESS_KEY_SECRET=UnwY0ClDkqBMLwPx3OJJiLYyk9xYLO
ANDROID_APP_KEY=30774987
ANDROID_APP_SECRET=297a0f231f1286a2de9aab097cc8ff5c
IOS_APP_KEY=30790728
IOS_APP_SECRET=4fd69ca084c67d4b5a8d15452f0af26a
APNS=PRODUCT
[AGORA]
APP_ID=6291d069123642d9929a49c734c50719
APP_CERTIFICATE=d5de40350aa54e60bcdce90c71e9598a
CUSTOMER_KEY=6b132c0ff7164560a2bc53fda06ea85a
CUSTOMER_SECRET=eedad2cd16d24834990d5450ace9f1ce
[CHECKOUT]
AUTHORIZATION=sk_fca6e213-b7df-4bd7-99f4-7c0a9f7c778c
URL=https://api.checkout.com/hosted-payments
H5=https://h5.whoisamy.shop/action/hiloHtml/22_05_30_recharge/topup.html
HILO_SECRET_KEY=sk_26806bf4-e6e3-45e2-a093-c72c5b53eaf5
[MATCH]
MATCH_FREE_TIME=60
MATCH_FREE_TIME_VIP=60
MATCH_ADD_TIME_FREE=90
MATCH_AGORA_TIME=30
MATCH_CYCLE=8
MATCH_USER_EXPIRES=480
MATCH_SUCCESS_WAIT_DURATION=10
MATCH_SUCCESS_SINGLE_WAIT_TIME_IN_SEC=12
MATCH_SUCCESS_DUAL_WAIT_TIME_IN_SEC=15
[ONLINE]
ONLINE_CYCLE=600
ONLINE_USER_EXPIRES=259200
[VIDEO]
VIDEO_DAILY_FREE_NUM=20
VIDEO_FREE_TIME=60
VIDEO_FREE_TIME_VIP=300
VIDEO_ADD_TIME_FREE=60
VIDEO_AGORA_TIME=30
VIDEO_MINUTE_NORMAL=60
VIDEO_MINUTE_UNION=60
[SESSION]
SESSION_DAILY_FREE_NUM=50
GUILD_USER_HELLO_DAY=30
[BEAN]
DIAMOND_BEAN_RATE=90
[GEM]
DIAMOND_GEM_RATE=10
[H5]
USER_LEVEL=https://h5.whoisamy.shop/action/hiloHtml/hiloUserLevel/index.html
GROUP_SUPPORT=https://h5.whoisamy.shop/action/activityhtml/21_12_06/page.html
LUCKY_WHEEL=https://h5.whoisamy.shop/action/activityhtml/21_12_30/page.html
WEEKLY_STAR=https://h5.whoisamy.shop/action/hiloHtml/lxt_h5/page.html
WEEKLY_CP=https://h5.whoisamy.shop/action/hiloHtml/Valentines_22_1_18/page.html
COUNTRY_STAR=https://h5.whoisamy.shop/action/hiloHtml/22_08_18_nation_star/page.html
NOBLE_BUY_IOS=https://h5.whoisamy.shop/action/hiloHtml/22_05_26_buy_nobility/page.html
NOBLE_BUY_IOS_AUDIT=https://h5.whoisamy.shop/action/hiloHtml/lxt_h5/page.html
GUILD_DATA_URL=https://h5.whoisamy.shop/action/hiloHtml/22_10_18_app_data_coins/index.html
MGR_GUILD_DATA_URL=https://h5.whoisamy.shop/action/hiloHtml/22_10_18_app_data_coins/union.html
RANKING_PINK_DIAMOND_URL=https://h5.whoisamy.shop/action/activitiesPage/2022_10_17HiloLiveH5/index.html
GROUP_POWER_GRADE_URL=https://h5.whoisamy.shop/action/hiloHtml/2023Activity/2023_3_21FamilyLevel/index.html
ID_URL=https://h5.whoisamy.shop/action/hiloHtml/new_upgrade/index.html
GROUP_POWER_ACT_URL=https://h5.whoisamy.shop/action/hiloHtml/2023Activity/2023_4_21FamilyMonth/index.html
SHEEP_H5_URL=https://h5.whoisamy.shop/action/slotRelease/sheep0322v1/index.html?game_id=hilo_sheep
[GROUPIM]
MSG_SORT_EXPIRE=1209600
MSG_SORT_SNAP=300
MSG_PARALLEL_SIZE=10
[GRADE]
CHARM_SPEED_VIP=15
ACTITY_SPEED_VIP=15
WEALTH_SPEED_VIP=15
[LIKE]
I_LIKE_NUM=500
I_LIKE_NUM_VIP=1000
I_LIKE_NUM_NOBLE=5000
[APPLEPAY]
PASSWORD=38702750a05c4cb09c9d6ca646835634
[REGISTER]
IMEI_TOTAL=5
IMEI_OAUTH=2
ACCOUNT_IP=100
ACCOUNT_IP_DURATION=21600
[BANNER]
GIFT_BANNER_LEVEL1=3000
GIFT_BANNER_LEVEL2=5000
GIFT_BANNER_LEVEL3=10000
[DIAMOND]
DAILY_LOGIN_IMEI_LIMIT=5
DAILY_LOGIN_IP_LIMIT=30
PRIVATE_GIFT_RETURN=1440
NEW_USER_INVITE_AWARD=5000
[LUCKY_WHEEL]
MINIMAL_PARTICIPANT=2
WAIT_TIMELONG=10
WINNER_DIAMOND_BANNER=200
[GROUP_CUSTOM_THEME]
PIC_LIMIT=50
DAY=10
[GIFT]
WALL_DIAMOND=2000
[DAILY]
LOGIN_COMMON=10
LOGIN_VIP=1000
[FRUIT_TYCOON]
BIG_WINNER_THRESDHOLD=30000
BIG_WINNER_LOW=10000
BIG_WINNER_HIGH=20000
POOL_RATIO=5
WATERMELON_RATIO=24
[ACTIVITY]
COUNTRY_STAR_POOL_RATIO=20
COUNTRY_STAR_ORDINARY_RATIO=20
[RISK_CONTROL]
USER_QPS_LIMIT=128
USER_URL_QPS_LIMIT=64
[PAYER_MAX]
URL=https://pay-gate.payermax.com/aggregate-pay-gate/api/gateway
KEY=503a970695756efa
MERCHANT_ID=SP11018326
BIZ_TYPE=CUSTOMIZE
VERSION=2.3
FRONT_CALLBACK_URL=https://www.hiloconn.com
SHOW_RESULT=1
EXPIRE_TIME=1800
LANGUAGE=en
[PAYPAL]
PAYPAL_CLIENT_ID=AXn-z2U6D2uKW0eJBoH3Hg0MzH6i8mLackAP9bcub2W_YmfMC-YBuPD3sTQgwJSecmAVtHIS9IsqBiIy
PAYPAL_SECRET_ID=EBNCFnSEwbteb8TDVtCMcOUcQBimG7hABmSe0bgC05HriWmje7cKFV2F4xI9pZnt1hDetKLnYxfmWYSY
RETURN_URL=https://apiv1.faceline.live/v1/callback/paypal
\ No newline at end of file
#!/usr/bin/bash
if [ $# -lt 1 ]
then
echo "Parameters missing."
echo "Usage: $0 <executable name>"
exit
fi
while :
do
$1
printf "$(date) : $1 return $?, wait for 5 seconds to restart\n"
sleep 5
done
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment