ソースを参照

update

guide_order
dengbiao 6ヶ月前
コミット
d821062586
28個のファイルの変更3627行の追加516行の削除
  1. +2
    -0
      app/cfg/init_cfg.go
  2. +0
    -313
      app/db/db_sys_mod.go
  3. +0
    -19
      app/db/dbs_map.go
  4. +25
    -0
      app/lib/auth/base.go
  5. +16
    -0
      app/md/applet.go
  6. +8
    -0
      app/md/instant_sms.go
  7. +26
    -0
      app/md/official_recommend_list.go
  8. +98
    -0
      app/md/oil.go
  9. +20
    -0
      app/md/phone_charge.go
  10. +222
    -0
      app/md/privilege_card.go
  11. +11
    -0
      app/md/publisher_info.go
  12. +41
    -0
      app/md/url.go
  13. +11
    -0
      app/md/word.go
  14. +1
    -2
      app/svc/svc_order_track_save_update.go
  15. +46
    -0
      app/utils/auth.go
  16. +421
    -0
      app/utils/cachesecond/base.go
  17. +107
    -0
      app/utils/cachesecond/cache/cache.go
  18. +86
    -0
      app/utils/cachesecond/cache/conv.go
  19. +241
    -0
      app/utils/cachesecond/cache/file.go
  20. +239
    -0
      app/utils/cachesecond/cache/memory.go
  21. +406
    -0
      app/utils/cachesecond/redis.go
  22. +622
    -0
      app/utils/cachesecond/redis_cluster.go
  23. +324
    -0
      app/utils/cachesecond/redis_pool.go
  24. +617
    -0
      app/utils/cachesecond/redis_pool_cluster.go
  25. +20
    -0
      app/utils/json.go
  26. +0
    -172
      consume/zhios_user_visit_ip_address_consume.go
  27. +17
    -4
      go.mod
  28. +0
    -6
      main.go

+ 2
- 0
app/cfg/init_cfg.go ファイルの表示

@@ -25,6 +25,7 @@ var (
Local bool
AppComm *AppCommCfg
WxappletFilepath *WxappletFilepathCfg
ArkID *ArkIDCfg
)

//初始化配置文件,将cfg.yml读入到内存
@@ -63,4 +64,5 @@ func InitCfg() {
ImBusinessRpc = &conf.ImBusinessRpc
ImLogicRpc = &conf.ImLogicRpc
WxappletFilepath = &conf.WxappletFilepath
ArkID = &conf.ArkID
}

+ 0
- 313
app/db/db_sys_mod.go ファイルの表示

@@ -2,16 +2,12 @@ package db

import (
"applet/app/db/model"
"applet/app/e"
"applet/app/utils"
"applet/app/utils/logx"
"errors"
"fmt"
"strconv"
"strings"

"github.com/gin-gonic/gin"
"github.com/tidwall/gjson"
"xorm.io/xorm"
)

@@ -253,281 +249,6 @@ func SysModFindByTemplateIDAndModNameWithIds(Db *xorm.Engine, ids []int, modName
return &m, nil
}

// SysModFindNavIsUsed 查找正在使用的底部导航栏模板
func SysModFindNavIsUsedByPlatform(c *gin.Context, Db *xorm.Engine, platform string) (*model.SysModule, error) {
var (
tm model.SysTemplate
m model.SysModule
)

mid := c.GetString("mid")
fmt.Println("===================================app_type", c.GetString("app_type"))
if c.GetString("app_type") != "" && c.GetString("app_type") != "daogou" {
var (
tempType string
)
switch c.GetString("app_type") {
case "o2o":
tempType = "o2o_store_bottomNav"

}

switch platform {
case "ios":
if has, err := Db.Where("is_use = 1 AND type = ? AND platform = 2 ", tempType).
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
appVersion := GetCloudBuild(c, platform)
if c.GetHeader("app_version_name") == appVersion && c.GetHeader("app_version_name") != "" {
m, err := GetCloudBundleByVersion(Db, appVersion, 2, 1)
if err != nil {
return nil, logx.Warn(err)
}
tm.Id = int(gjson.Get(m.TemplateDuringAudit, "bottom").Int())
}
case "android":
has, err := Db.Where("is_use = 1 AND type = ? AND platform = 2 ", tempType).Cols("id,uid,name,is_use,is_system").Get(&tm)
if err != nil || has == false {
return nil, logx.Warn(err)
}
fmt.Println("===================================app_type", tm)

appVersion := GetCloudBuild(c, platform)
fmt.Println("===================================app_type", appVersion)

if appVersion != "" && c.GetHeader("app_version_name") == appVersion {
m, err := GetCloudBundleByVersion(Db, appVersion, 1, 1)
if err != nil {
return nil, logx.Warn(err)
}
fmt.Println("===================================app_type", m)

tm.Id = int(gjson.Get(m.TemplateDuringAudit, "bottom").Int())
}
case "wx_applet", "wap":
if has, err := Db.Where("is_use = 1 AND type = ? AND platform = 4 ", tempType).
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
case "baidu_applet":
if has, err := Db.Where("is_use = 1 AND type = ? AND platform = 4 ", tempType).
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
case "toutiao_applet":
if has, err := Db.Where("is_use = 1 AND type = ? AND platform = 4 ", tempType).
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
case "alipay_applet":
if has, err := Db.Where("is_use = 1 AND type = ? AND platform = 4 ", tempType).
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
default:
return &m, errors.New("Platform not support")
}
if has, err := Db.Where("state = 1 AND template_id = ?", tm.Id).
Get(&m); err != nil || has == false {
return nil, logx.Warn(err)
}

fmt.Println("===================================app_type", m)
if tempType == "o2o_store_bottomNav" {
bottomMap := make(map[string]interface{})
utils.Unserialize([]byte(m.Data), &bottomMap)
list, ok := bottomMap["list"]
if ok {
m.Data = string(utils.MarshalJSONCamelCase2JsonSnakeCase(utils.SerializeStr(list)))
}
}
mm, err := sysModFormat(c, &m)
if err != nil {
return nil, err
}
return mm.(*model.SysModule), nil
}
switch platform {
case "ios":
if has, err := Db.Where("is_use = 1 AND type = 'bottom' AND platform = 2 ").
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
appVersion := GetCloudBuild(c, platform)
if c.GetHeader("app_version_name") == appVersion && c.GetHeader("app_version_name") != "" {
m, err := GetCloudBundleByVersion(Db, appVersion, 2, 0)
if err != nil {
return nil, logx.Warn(err)
}
tm.Id = int(gjson.Get(m.TemplateDuringAudit, "bottom").Int())
}

if has, err := Db.Where("state = 1 AND template_id = ? AND mod_name = 'bottom_nav'", tm.Id).
Get(&m); err != nil || has == false {
return nil, logx.Warn(err)
}
mm, err := sysModFormat(c, &m)
if err != nil {
return nil, err
}
return mm.(*model.SysModule), nil
case "android":
has, err := Db.Where("is_use = 1 AND type = 'bottom' AND platform = 2 ").Cols("id,uid,name,is_use,is_system").Get(&tm)
if err != nil || has == false {
return nil, logx.Warn(err)
}
appVersion := GetCloudBuild(c, platform)
if appVersion != "" && c.GetHeader("app_version_name") == appVersion {
m, err := GetCloudBundleByVersion(Db, appVersion, 1, 0)
if err != nil {
return nil, logx.Warn(err)
}
tm.Id = int(gjson.Get(m.TemplateDuringAudit, "bottom").Int())
}
if has, err := Db.Where("state = 1 AND template_id = ? AND mod_name = 'bottom_nav'", tm.Id).
Get(&m); err != nil || has == false {
return nil, logx.Warn(err)
}
mm, err := sysModFormat(c, &m)
if err != nil {
return nil, err
}
return mm.(*model.SysModule), nil
case "wx_applet", "wap":
wxAppletCfg := GetAppletKey(c, Db)
id := utils.StrToInt(wxAppletCfg["bottom_nav_css_id"])
if id == 0 {
return nil, e.NewErr(400, "找不到模板配置")
}
if has, err := Db.Where("state = 1 AND template_id = ? AND mod_name = 'bottom_nav'", id).
Get(&m); err != nil || has == false {
return nil, logx.Warn(err)
}
mm, err := sysModFormat(c, &m)
if err != nil {
return nil, err
}
return mm.(*model.SysModule), nil
case "baidu_applet":
if has, err := Db.Where("is_use = 1 AND type = 'bottom' AND platform = 4 ").
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
appVersion := SysCfgGetWithDb(Db, mid, "baidu_audit_version")

if appVersion != "" && c.GetHeader("app_version_name") == appVersion {
m := SysCfgGetWithDb(Db, mid, "baidu_audit_template")
if m == "" {
return nil, e.NewErr(400, "找不到模板配置")
}
tm.Id = int(gjson.Get(m, "bottom").Int())
}
if has, err := Db.Where("state = 1 AND template_id = ? AND mod_name = 'bottom_nav'", tm.Id).
Get(&m); err != nil || has == false {
return nil, logx.Warn(err)
}
mm, err := sysModFormat(c, &m)
if err != nil {
return nil, err
}
return mm.(*model.SysModule), nil
case "toutiao_applet":
if has, err := Db.Where("is_use = 1 AND type = 'bottom' AND platform = 4 ").
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
appVersion := SysCfgGetWithDb(Db, mid, "tt_audit_version")
if appVersion != "" && c.GetHeader("app_version_name") == appVersion {
m := SysCfgGetWithDb(Db, mid, "tt_audit_template")
if m == "" {
return nil, errors.New("找不到模板配置")
}
tm.Id = int(gjson.Get(m, "bottom").Int())
}
if has, err := Db.Where("state = 1 AND template_id = ? AND mod_name = 'bottom_nav'", tm.Id).
Get(&m); err != nil || has == false {
return nil, logx.Warn(err)
}
mm, err := sysModFormat(c, &m)
if err != nil {
return nil, err
}
return mm.(*model.SysModule), nil
case "alipay_applet":
if has, err := Db.Where("is_use = 1 AND type = 'bottom' AND platform = 4 ").
Cols("id,uid,name,is_use,is_system").
Get(&tm); err != nil || has == false {
return nil, logx.Warn(err)
}
appVersion := SysCfgGetWithDb(Db, mid, "zfb_audit_version")
if appVersion != "" && c.GetHeader("app_version_name") == appVersion {
m := SysCfgGetWithDb(Db, mid, "zfb_audit_template")
if m == "" {
return nil, errors.New("找不到模板配置")
}
tm.Id = int(gjson.Get(m, "bottom").Int())
}
if has, err := Db.Where("state = 1 AND template_id = ? AND mod_name = 'bottom_nav'", tm.Id).
Get(&m); err != nil || has == false {
return nil, logx.Warn(err)
}
mm, err := sysModFormat(c, &m)
if err != nil {
return nil, err
}
return mm.(*model.SysModule), nil
default:
return &m, errors.New("Platform not support")
}

}

// O2oBusinessSysModFindNavIsUsedByPlatform O2o商家端小程序查找正在使用的底部导航栏模板
func O2oBusinessSysModFindNavIsUsedByPlatform(c *gin.Context, Db *xorm.Engine, merchantId string) (*model.O2oBusinessSysModule, error) {
var (
//tm model.O2oBusinessSysTemplate
m model.O2oBusinessSysModule
//btm model.O2oBusinessSysTemplateAndMerchant
)
kind := "1"
platform := c.GetHeader("platform")
if platform == "wx_applet" {
kind = "bstm.type=2"
} else {
kind = "(bstm.type=1 OR bstm.type=0)"
}
sql := `SELECT * FROM o2o_business_applet_sys_template_and_merchant bstm LEFT JOIN o2o_business_sys_template bst ON bstm.template_id=bst.id WHERE %s`
where := "bstm.merchant_id=" + merchantId + " AND " + kind
sql = fmt.Sprintf(sql, where)
result, err := QueryNativeString(DBs[c.GetString("mid")], sql)
utils.FilePutContents("test123sql", sql)
utils.FilePutContents("test123", utils.SerializeStr(result))
if len(result) == 0 {
return nil, e.NewErrCode(e.ERR_NO_DATA)
}

if has, err := Db.Where("state = 1 AND template_id = ? AND mod_name = 'bottom'", result[0]["template_id"]).
Get(&m); err != nil || has == false {
return nil, logx.Warn(err)
}
utils.FilePutContents("test1234", utils.SerializeStr(m))
mm, err := o2oMerchantSysModFormat(c, &m)
utils.FilePutContents("test1235", utils.SerializeStr(mm))
if err != nil {
return nil, err
}
return mm.(*model.O2oBusinessSysModule), nil
}

// SysModFindBySkipIdentifierAndModName is 根据mod_name和位置 查找对应模块
func SysModFindBySkipIdentifierAndModName(c *gin.Context, Db *xorm.Engine, name string, modName string) (*model.SysModule, error) {
var m model.SysModule
@@ -667,40 +388,6 @@ func StringByReplace(c *gin.Context, skip string) string {
return skip
}

//公共处理modSkip的链接 首页弹窗
func SysModSkipByReplace(c *gin.Context, mod *model.SysPopup) *model.SysPopup {
//替换链接的一些参数
if strings.Contains(mod.Skip, "[replace_APP_URL]") {
mod.Skip = strings.Replace(mod.Skip, "[replace_APP_URL]", c.GetString("domain_wap_base"), -1)
}
if strings.Contains(mod.Skip, "[replace_masterId]") {
mod.Skip = strings.Replace(mod.Skip, "[replace_masterId]", c.GetString("mid"), -1)
}
if strings.Contains(mod.Skip, "[replace_platform]") {
mod.Skip = strings.Replace(mod.Skip, "[replace_platform]", c.GetHeader("Platform"), -1)
}
if strings.Contains(mod.Skip, "优惠卷") {
mod.Skip = strings.Replace(mod.Skip, "优惠卷", "优惠券", -1)
}
if strings.Contains(mod.Skip, "[replace_uid]") {
token := c.GetHeader("Authorization")
// 按空格分割
parts := strings.SplitN(token, " ", 2)
if len(parts) == 2 && parts[0] == "Bearer" {
// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它
mc, _ := utils.ParseToken(parts[1])
mod.Skip = strings.Replace(mod.Skip, "[replace_uid]", strconv.Itoa(mc.UID), -1)
}
}

//if strings.Contains(mod.Data, "\"child_category_id") && strings.Contains(mod.Data, "\"category_id") {
// //如果存在这两个字段,要换一下
// mod.Data = strings.ReplaceAll(mod.Data, "\"category_id", "\"null_category_id")
// mod.Data = strings.ReplaceAll(mod.Data, "\"child_category_id", "\"category_id")
//}
return mod
}

//公共处理modData的链接
func SysModDataByReplaceSecond(c *gin.Context, mod *model.SysModule) *model.SysModule {
//替换链接的一些参数


+ 0
- 19
app/db/dbs_map.go ファイルの表示

@@ -81,25 +81,6 @@ func GetAllDatabasePrd() *[]model.DbMapping {
logx.Warn(err)
return nil
}
var mm []model.SupplyDbMapping
if err := Db.Where("deleted_at != ? AND is_dev = '0' ", 1).Find(&mm); err != nil || len(mm) == 0 {
logx.Warn(err)
return nil
}
for _, v := range mm {
m = append(m, model.DbMapping{
DbMasterId: v.DbMasterId,
DbHost: v.DbHost,
DbUsername: v.DbUsername,
DbPassword: v.DbPassword,
DbName: v.DbName,
ExternalMysql: v.ExternalMysql,
IsDev: v.IsDev,
CreatedAt: v.CreatedAt,
UpdatedAt: v.UpdatedAt,
DeletedAt: v.DeletedAt,
})
}
return &m
}



+ 25
- 0
app/lib/auth/base.go ファイルの表示

@@ -0,0 +1,25 @@
package auth

import (
"time"

"github.com/dgrijalva/jwt-go"
)

// TokenExpireDuration is jwt 过期时间
const TokenExpireDuration = time.Hour * 4380

const RefreshTokenExpireDuration = time.Hour * 4380

var Secret = []byte("zyos")

// JWTUser 如果想要保存更多信息,都可以添加到这个结构体中
type JWTUser struct {
UID int `json:"uid"`
Username string `json:"username"`
Phone string `json:"phone"`
AppName string `json:"app_name"`
MiniOpenID string `json:"mini_open_id"` // 小程序的open_id
MiniSK string `json:"mini_session_key"` // 小程序的session_key
jwt.StandardClaims
}

+ 16
- 0
app/md/applet.go ファイルの表示

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

const (
/* 微信京东小程序 */
APPLET_JD_ID = "wx91d27dbf599dff74"
APPLET_JD_URL = "pages/union/proxy/proxy?spreadUrl=%s&EA_PTAG="
/* 唯品会 */
APPLET_VIP_ID = "wxe9714e742209d35f"
/* 考拉 */
APPLET_KL_ID = "wx9180a45a676eed94"
APPLET_KL_URL = "package-product/pages/index?dastr=__da_dad3e203_5d016fd6a5b92c00&zkTargetUrl=https%3A%2F%2Fm-goods.kaola.com%2Fproduct%2F{ITEM_ID}.html"
APPLET_KL_ACTIVITY_URL = "package-product/pages/index?dastr=__da_dad3e203_5d016fd6a5b92c00&zkTargetUrl={URL}"

/* 拼多多 */
APPLET_PDD_ID = "wx32540bd863b27570"
)

+ 8
- 0
app/md/instant_sms.go ファイルの表示

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

type InstantSms struct {
UseNum string `json:"use_num"`
Num string `json:"num"`
LeaveNum string `json:"leave_num"`
EndNum string `json:"end_num"`
}

+ 26
- 0
app/md/official_recommend_list.go ファイルの表示

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

// 美团

type OfficialRecommendUrl struct {
Url string // 链接
WxQrcodeUrl string
WxMiniprogramPath string
AppUrl string
Appid string
Id string //小程序原始id
TaobaoWord string
ClickUrl string
Seq string
Title string
Content string
SuccessContent string
}
type ActivityPlatform struct {
ActivityPlatformId string `json:"activity_id"`
MaterialId string `json:"material_id"`
ActivityPlatformUrl string `json:"url"`
}
type KaolaActivityList struct {
Url string `json:"shareLink"`
}

+ 98
- 0
app/md/oil.go ファイルの表示

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

type OilRequest struct {
ItemName string `json:"item_name"` // 油号
CityName string `json:"city_name"` // 城市
Lat string `json:"lat"` // 纬度
Lng string `json:"lng"` // 经度
Sort string `json:"sort"` // 排序
BrandName string `json:"brand_name"` // 品牌
P string `json:"p"` // 页码
Mobile string `json:"mobile"` // 手机号
Id string `json:"id"` // id
CategoryId string `json:"category_id"` //id 多个是逗号隔开
Pvd string `json:"pvd"` //类型
IsReturnJh string `json:"is_return_jh"` //是否返回聚合链接
}

type OilList struct {
Address string `json:"address"`
BrandName string `json:"brand_name"`
CityName string `json:"city_name"`
CostPrice string `json:"cost_price"`
Dis string `json:"dis"`
ID string `json:"id"`
InfoList string `json:"info_list"`
ItemName string `json:"item_name"`
Label []string `json:"label"`
Lat string `json:"lat"`
Lng string `json:"lng"`
Logo string `json:"logo"`
Name string `json:"name"`
OilID string `json:"oil_id"`
StorePrice string `json:"store_price"`
UpdateTime string `json:"update_time"`
VipPrice string `json:"vip_price"`
YhPrice string `json:"yh_price"`
}

type OilListResult struct {
Address string `json:"address"`
CityName string `json:"city_name"`
CostPrice string `json:"cost_price"`
Dis string `json:"dis"`
ID string `json:"id"`
Label []string `json:"label"`
Logo string `json:"logo"`
Name string `json:"name"`
StorePrice string `json:"store_price"`
Lat string `json:"lat"`
Lng string `json:"lng"`
}

type OilDetail struct {
Url string `json:"Url"`
}

type OilCarouselList struct {
Img string `json:"img"`
ImgURL string `json:"img_url"`
Index int `json:"index"`
IsJump string `json:"is_jump"`
IsShow string `json:"is_show"`
Name string `json:"name"`
RequiredLogin string `json:"required_login"`
RequiredTaobaoAuth string `json:"required_taobao_auth"`
SkipIdentifier string `json:"skip_identifier"`
SkipName string `json:"skip_name"`
Data CommModData `json:"data"`
}

type OilStyle struct {
BtnBgColor string `json:"btn_bg_color"`
BtnStrColor string `json:"btn_str_color"`
CarouselList []OilCarouselList `json:"carousel_list"`
HeaderBg struct {
AssistColor string `json:"assist_color"`
MainColor string `json:"main_color"`
MinColor string `json:"min_color"`
} `json:"header_bg"`
NavImg string `json:"nav_img"`
NavImgUrl string `json:"nav_img_url"`
NavStrColor string `json:"nav_str_color"`
PriceStrColor string `json:"price_str_color"`
Title string `json:"title"`
TitleColor string `json:"title_color"`
ItemNameList []struct {
Name string `json:"name"`
Type string `json:"type"`
} `json:"item_name_list"`
BrandNameList []struct {
Name string `json:"name"`
Type string `json:"type"`
} `json:"brand_name_list"`
SortNameList []struct {
Name string `json:"name"`
Type string `json:"type"`
} `json:"sort_name_list"`
}

+ 20
- 0
app/md/phone_charge.go ファイルの表示

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

type GetChargeMoney struct {
PlatformMoney string `json:"platform_money"`
UserMoney string `json:"user_money"`
PhoneChargeDiscount string `json:"phone_charge_discount"`
PhoneChargeAddPrice string `json:"phone_charge_add_price"`
PhoneChargePriceList string `json:"phone_charge_price_list"`
Goods []PhoneGoodsData `json:"goods"`
}
type PhoneGoodsData struct {
Id string `json:"id"`
Capacity string `json:"capacity"`
Price string `json:"price"`
}
type PhoneChargeData struct {
Phone string `json:"phone"`
PhoneInfo string `json:"phone_info"`
List []*PrivilegeCardGoodsNew `json:"list"`
}

+ 222
- 0
app/md/privilege_card.go ファイルの表示

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

const (
UNPAID = "0"
PAID = "1"
REFUND = "2"
EXPIRE = "3"
CHECKSUCCESS = "4"
)

var ORD_STATE_LIST = map[string]string{
UNPAID: "未支付",
PAID: "付款成功",
REFUND: "已退款",
EXPIRE: "已失效",
CHECKSUCCESS: "充值成功",
}

type PrivilegeCardGoods struct {
ID string `json:"id"`
GID string `json:"g_id"`
Title string `json:"title"`
OfficialPrice string `json:"official_price"`
PlatPrice string `json:"plat_price"`
Times string `json:"times"`
SpecID string `json:"spec_id"`
SpecImg string `json:"spec_img"`
UpdateTime string `json:"update_time"`
LID string `json:"l_id"`
Type string `json:"type"`
IsDelete string `json:"is_delete"`
TypeID string `json:"type_id"`
IsShowIdnum string `json:"is_show_idnum"`
}

type PrivilegeCardBrand struct {
ID string `json:"id"`
AccountType string `json:"account_type"`
GID string `json:"g_id"`
GoodsLogo string `json:"goods_logo"`
GName string `json:"g_name"`
UpdateTime string `json:"update_time"`
Type string `json:"type"`
Xuzhi string `json:"xuzhi"`
IsDelete string `json:"is_delete"`
TypeID string `json:"type_id"`
IsShowArea string `json:"is_show_area"`
}

//type b struct {
// IsOpen string `json:"is_open"`
// CardName string `json:"card_name"`
// ConditionType string `json:"condition_type"`
// ConditionData `json:"condition_data"`
// BalanceNoticeLimit string `json:"balance_notice_limit"`
// PaymentAvailable []string `json:"payment_available"`
// NewcomersGUIDURL string `json:"newcomers_guid_url"`
//}

type PrivilegeCardCfg struct {
IsOpen string `json:"is_open"`
CardName string `json:"card_name"`
ConditionType string `json:"condition_type"`
ConditionData interface{} `json:"condition_data"`
RegisterCondition struct {
InviteCode struct {
Popup string `json:"popup"`
ShouldInput string `json:"should_input"`
} `json:"invite_code"`
CardKey struct {
Popup string `json:"popup"`
ShouldInput string `json:"should_input"`
} `json:"card_key"`
} `json:"register_condition"`
BalanceNoticeLimit string `json:"balance_notice_limit"`
PaymentAvailable []string `json:"payment_available"`
NewcomersGUIDURL string `json:"newcomers_guid_url"`
}

// PrivilegeCardConditionCfg 2.条件开通
type PrivilegeCardConditionCfg []struct {
Type string `json:"type"`
Level string `json:"level"`
}

// PrivilegeCardNeedMoneyCfg 3.付费开通
type PrivilegeCardNeedMoneyCfg struct {
Type string `json:"type"` // 类型:1实体卡 2虚拟卡
Cost []struct {
DateType string `json:"date_type"`
CostPrice string `json:"cost_price"`
OriginalPrice string `json:"original_price"`
IsOn string `json:"is_on"`
} `json:"cost"` // 价格设置
GivenData []PrivilegeOpenCardGivenData `json:"given_data"` // 赠送设置
}

type PrivilegeOpenCardGivenData struct {
Type string `json:"type"`
Data struct {
Level string `json:"level"`
Days string `json:"days"`
IsForever string `json:"is_forever"`
} `json:"data"`
}
type PrivilegeOpenCardCoinCouponData struct {
CouponAmount string `json:"coupon_amount"`
CouponAmountTypeStr string `json:"coupon_amount_type_str"`
CouponAmountOnoff string `json:"coupon_amount_onoff"`
VirtualCoinList []VirtualCoinList `json:"virtual_coin_list"`
VirtualCoinOnoff string `json:"virtual_coin_onoff"`
Days string `json:"days"`
IsForever string `json:"is_forever"`
Level string `json:"level"`
LvOnoff string `json:"lv_onoff"`
IsGiven int `json:"is_given"`
}
type PrivilegeOpenCardLvData struct {
Days string `json:"days"`
IsForever string `json:"is_forever"`
Level string `json:"level"`
LvOnoff string `json:"lv_onoff"`
}
type VirtualCoinList struct {
ID string `json:"id"`
Name string `json:"name"`
Value string `json:"value"`
}

type PrivilegeCardGoodsNew struct {
Id int `json:"id" xorm:"not null pk autoincr INT(11)"`
ZhimengId int `json:"zhimeng_id" xorm:"not null default 0 comment('智盟ID') INT(11)"`
ThirdId int `json:"third_id" xorm:"not null default 0 comment('三方平台ID') INT(11)"`
Name string `json:"name" xorm:"not null default '' comment('商品名称') VARCHAR(255)"`
OldName string `json:"old_name" xorm:"not null default '' comment('商品名称') VARCHAR(255)"`
GoodsImg string `json:"goods_img" xorm:"not null default '' comment('商品图片') VARCHAR(255)"`
BrandId int `json:"brand_id" xorm:"not null default 0 comment('品牌ID') INT(11)"`
Times string `json:"times" xorm:"not null default '' comment('时长') VARCHAR(255)"`
CateId int `json:"cate_id" xorm:"not null default 0 comment('商品分类ID') INT(11)"`
MarkupMode int `json:"markup_mode" xorm:"not null default 0 comment('加价模式 0为利润空间1为进货价') TINYINT(1)"`
MarkupRate int `json:"markup_rate" xorm:"not null default 0 comment('加价比例') DECIMAL(5,2)"`
OfficialPrice string `json:"official_price" xorm:"not null default 0.00 comment('原价') DECIMAL(10,2)"`
PlatformPrice string `json:"platform_price" xorm:"not null default 0.00 comment('进货价') DECIMAL(10,2)"`
FinalPrice string `json:"final_price" xorm:"not null default 0.00 comment('销售价') DECIMAL(10,2)"`
OldFinalPrice string `json:"old_final_price" xorm:"not null default 0.00 comment('销售价') DECIMAL(10,2)"`
Type string `json:"type" xorm:"not null default '' comment('类型') VARCHAR(255)"`
TypeId string `json:"type_id" xorm:"not null default '' comment('类型id') VARCHAR(255)"`
IsShow int `json:"is_show" xorm:"not null default 1 comment('是否显示') TINYINT(1)"`
Sort int `json:"sort" xorm:"default 0 comment('排序') INT(11)"`
CreatedAt int `json:"created_at" xorm:"not null default 0 INT(11)"`
UpdatedAt int `json:"updated_at" xorm:"not null default 0 INT(11)"`
DeletedAt int `json:"deleted_at" xorm:"not null default 0 INT(11)"`
Data string `json:"data" xorm:"not null comment('拓展用') LONGTEXT"`
GoodsSales int `json:"goods_sales" xorm:"not null default 0 INT(11)"`
IsCanBuy string `json:"is_can_buy"` //是否能购买
IsShowCouponList string `json:"is_show_coupon_list"` //是否展示优惠券弹出
UserCouponAmount string `json:"user_coupon_amount"` //优惠券额度
Coupon string `json:"coupon"` //
IsShowIdnum string `json:"is_show_idnum"`
AreaType string `json:"area_type"`
CouponId string `json:"coupon_id"`
PriceStr string `json:"price_str"`
}

type PrivilegeCheckPerm struct {
State bool `json:"state"`
Reason string `json:"reason"`
ConditionType string `json:"condition_type"`
ConditionData interface{} `json:"condition_data"`
BtnStr string `json:"btn_str"`
Skip PrivilegeCheckSkip `json:"skip"`
}
type PrivilegeCheckSkip struct {
Data CommModData `json:"data"`
IsJump string `json:"is_jump"`
Name string `json:"name"`
RequiredLogin string `json:"required_login"`
RequiredTaobaoAuth string `json:"required_taobao_auth"`
SkipIdentifier string `json:"skip_identifier"`
SkipName string `json:"skip_name"`
URL string `json:"url"`
}

type PrivilegeAfterSuccessPopup struct {
BgImg string `json:"bg_img"`
BtnImg string `json:"btn_img"`
Skip SkipData `json:"skip"`
SubTip string `json:"sub_tip"`
Tip string `json:"tip"`
TipType string `json:"tip_type"`
TextTipInfo PrivilegeAfterSuccessPopupText `json:"text_tip_info"`
}
type PrivilegeAfterSuccessPopupText struct {
TopTitle string `json:"title"`
Content string `json:"content"`
SecondContent string `json:"second_content"`
BtnStr string `json:"btn_str"`
}
type PrivilegeCardArea struct {
IsShowDistrict string `json:"is_show_district"`
CountryArea []PrivilegeCardAreaList `json:"country_area"`
SouthArea []PrivilegeCardAreaList `json:"south_area"`
}
type PrivilegeCardAreaList struct {
Id int64 `json:"id"`
Key string `json:"key"`
Value string `json:"value"`
CityList []PrivilegeCardAreaCityList `json:"city_list"`
}
type PrivilegeCardAreaCityList struct {
Id int64 `json:"id"`

Key string `json:"key"`
Value string `json:"value"`
DistrictList []PrivilegeCardAreaDistrictList `json:"district_list"`
}
type PrivilegeCardAreaDistrictList struct {
Id int64 `json:"id"`

Key string `json:"key"`
Value string `json:"value"`
}

+ 11
- 0
app/md/publisher_info.go ファイルの表示

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

// 会员备案信息

type PublisherInfo struct {
RelationId string // 渠道id
SpecialId string // 会员运营id
ExternalId string // 自定义参数
Rtag string // 备注

}

+ 41
- 0
app/md/url.go ファイルの表示

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

type ExtraData struct {
UnionId string `json:"unionId"`
Tc1 string `json:"tc1"`
Tc2 string `json:"tc2"`
}

// 转链后链接
type ConvertedUrls struct {
StopStr string `json:"stop_str"`
IsStop string `json:"is_stop"`
IsDown string `json:"is_down"`
Tkl string `json:"tkl"`
ShortTkl string `json:"short_tkl"`
ItemId string `json:"item_id"`
ItemUrl string `json:"item_url"`
NumGoodsId string `json:"num_goods_id"`
URL string `json:"url"` // 短链接
ShortenURL string `json:"open_app_url"` // 会打开app的长链接
NoOpenAppURL string `json:"no_open_app_url"` // 不会打开app的长链接
AppURL string `json:"app_url"` // app 链接 pinduoduo://
HasCoupon bool `json:"has_coupon"` // 是否有优惠券
CommissionRate string `json:"commission_rate"` // 利润比例
ShareURL string `json:"share_url"` // 分享的URL
WeChatTaobaoURL string `json:"wechat_taobao_url"` // 淘宝分享到微信用的url
WeChatMiniURL string `json:"wechat_mini_url"` // 微信小程序转链地址
WeChatMiniAPPID string `json:"wechat_mini_appid"` // 微信appid
PID string `json:"pid"` // 推广位
PvdId string `json:"pvd_id"` // 供应商联盟ID
TaoBaoWord string `json:"taobao_word"` // 淘口令TaoBaoWord string `json:"taobao_word"` // 淘口令
ExtraData ExtraData `json:"extraData"` //考拉用来跟踪用户的
TbShareId int64 `json:"tb_share_id"` //淘宝活动时的渠道id 组合方式
IsHasCouponAmount int `json:"is_has_coupon_amount"` //是否有优惠券额度
ClickUrl string `json:"click_url"`
QrcodeUrl string `json:"qrcode_url"`
Content string `json:"content"`
PvdName string `json:"pvd_name"`
NewPid string `json:"new_pid"`
H5Url string `json:"h5_url"`
}

+ 11
- 0
app/md/word.go ファイルの表示

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

// 淘口令

type TaobaoWord struct {
Text string // 文本
Code string // 短码
}
type TaobaoWordGid struct {
Gid string // 商品id
}

+ 1
- 2
app/svc/svc_order_track_save_update.go ファイルの表示

@@ -4,7 +4,6 @@ import (
"applet/app/cfg"
"applet/app/md"
"applet/app/utils/cache"
md2 "applet/consume/md"
"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
"fmt"
"github.com/tidwall/gjson"
@@ -233,7 +232,7 @@ func OrderSaveUpdate(eg *xorm.Engine, pvd string, ordData *[]md.OrderInfo, opts
}
eg.Where("id=?", m.Id).Cols("sale,stock").Update(m)
} else if storeOrder != nil && utils.StrToFloat64(storeOrder.DeductPrice) > 0 && storeOrder.DeductState == 1 {
arg := md2.ZhiosGuideStoreOrder{
arg := md.ZhiosGuideStoreOrder{
Uid: utils.IntToStr(v.Uid),
Mid: dbName,
Oid: utils.Int64ToStr(v.OrdId),


+ 46
- 0
app/utils/auth.go ファイルの表示

@@ -0,0 +1,46 @@
package utils

import (
"errors"
"time"

"applet/app/lib/auth"

"github.com/dgrijalva/jwt-go"
)

// GenToken 生成JWT
func GenToken(uid int, username, phone, appname, MiniOpenID, MiniSK string) (string, error) {
// 创建一个我们自己的声明
c := auth.JWTUser{
uid,
username,
phone,
appname,
MiniOpenID,
MiniSK,
jwt.StandardClaims{
ExpiresAt: time.Now().Add(auth.TokenExpireDuration).Unix(), // 过期时间
Issuer: "zyos", // 签发人
},
}
// 使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
// 使用指定的secret签名并获得完整的编码后的字符串token
return token.SignedString(auth.Secret)
}

// ParseToken 解析JWT
func ParseToken(tokenString string) (*auth.JWTUser, error) {
// 解析token
token, err := jwt.ParseWithClaims(tokenString, &auth.JWTUser{}, func(token *jwt.Token) (i interface{}, err error) {
return auth.Secret, nil
})
if err != nil {
return nil, err
}
if claims, ok := token.Claims.(*auth.JWTUser); ok && token.Valid { // 校验token
return claims, nil
}
return nil, errors.New("invalid token")
}

+ 421
- 0
app/utils/cachesecond/base.go ファイルの表示

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

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

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

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

// 以下为提供类型转换

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

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

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

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

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

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

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

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

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

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

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

return value, err
}

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

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

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

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

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

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

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

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

return value, err
}

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

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

+ 107
- 0
app/utils/cachesecond/cache/cache.go ファイルの表示

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

import (
"fmt"
"time"
)

var c Cache

type Cache interface {
// get cached value by key.
Get(key string) interface{}
// GetMulti is a batch version of Get.
GetMulti(keys []string) []interface{}
// set cached value with key and expire time.
Put(key string, val interface{}, timeout time.Duration) error
// delete cached value by key.
Delete(key string) error
// increase cached int value by key, as a counter.
Incr(key string) error
// decrease cached int value by key, as a counter.
Decr(key string) error
// check if cached value exists or not.
IsExist(key string) bool
// clear all cache.
ClearAll() error
// start gc routine based on config string settings.
StartAndGC(config string) error
}

// Instance is a function create a new Cache Instance
type Instance func() Cache

var adapters = make(map[string]Instance)

// Register makes a cache adapter available by the adapter name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func Register(name string, adapter Instance) {
if adapter == nil {
panic("cache: Register adapter is nil")
}
if _, ok := adapters[name]; ok {
panic("cache: Register called twice for adapter " + name)
}
adapters[name] = adapter
}

// NewCache Create a new cache driver by adapter name and config string.
// config need to be correct JSON as string: {"interval":360}.
// it will start gc automatically.
func NewCache(adapterName, config string) (adapter Cache, err error) {
instanceFunc, ok := adapters[adapterName]
if !ok {
err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName)
return
}
adapter = instanceFunc()
err = adapter.StartAndGC(config)
if err != nil {
adapter = nil
}
return
}

func InitCache(adapterName, config string) (err error) {
instanceFunc, ok := adapters[adapterName]
if !ok {
err = fmt.Errorf("cache: unknown adapter name %q (forgot to import?)", adapterName)
return
}
c = instanceFunc()
err = c.StartAndGC(config)
if err != nil {
c = nil
}
return
}

func Get(key string) interface{} {
return c.Get(key)
}

func GetMulti(keys []string) []interface{} {
return c.GetMulti(keys)
}
func Put(key string, val interface{}, ttl time.Duration) error {
return c.Put(key, val, ttl)
}
func Delete(key string) error {
return c.Delete(key)
}
func Incr(key string) error {
return c.Incr(key)
}
func Decr(key string) error {
return c.Decr(key)
}
func IsExist(key string) bool {
return c.IsExist(key)
}
func ClearAll() error {
return c.ClearAll()
}
func StartAndGC(cfg string) error {
return c.StartAndGC(cfg)
}

+ 86
- 0
app/utils/cachesecond/cache/conv.go ファイルの表示

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

import (
"fmt"
"strconv"
)

// GetString convert interface to string.
func GetString(v interface{}) string {
switch result := v.(type) {
case string:
return result
case []byte:
return string(result)
default:
if v != nil {
return fmt.Sprint(result)
}
}
return ""
}

// GetInt convert interface to int.
func GetInt(v interface{}) int {
switch result := v.(type) {
case int:
return result
case int32:
return int(result)
case int64:
return int(result)
default:
if d := GetString(v); d != "" {
value, _ := strconv.Atoi(d)
return value
}
}
return 0
}

// GetInt64 convert interface to int64.
func GetInt64(v interface{}) int64 {
switch result := v.(type) {
case int:
return int64(result)
case int32:
return int64(result)
case int64:
return result
default:

if d := GetString(v); d != "" {
value, _ := strconv.ParseInt(d, 10, 64)
return value
}
}
return 0
}

// GetFloat64 convert interface to float64.
func GetFloat64(v interface{}) float64 {
switch result := v.(type) {
case float64:
return result
default:
if d := GetString(v); d != "" {
value, _ := strconv.ParseFloat(d, 64)
return value
}
}
return 0
}

// GetBool convert interface to bool.
func GetBool(v interface{}) bool {
switch result := v.(type) {
case bool:
return result
default:
if d := GetString(v); d != "" {
value, _ := strconv.ParseBool(d)
return value
}
}
return false
}

+ 241
- 0
app/utils/cachesecond/cache/file.go ファイルの表示

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

import (
"bytes"
"crypto/md5"
"encoding/gob"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"strconv"
"time"
)

// FileCacheItem is basic unit of file cache adapter.
// it contains data and expire time.
type FileCacheItem struct {
Data interface{}
LastAccess time.Time
Expired time.Time
}

// FileCache Config
var (
FileCachePath = "cache" // cache directory
FileCacheFileSuffix = ".bin" // cache file suffix
FileCacheDirectoryLevel = 2 // cache file deep level if auto generated cache files.
FileCacheEmbedExpiry time.Duration // cache expire time, default is no expire forever.
)

// FileCache is cache adapter for file storage.
type FileCache struct {
CachePath string
FileSuffix string
DirectoryLevel int
EmbedExpiry int
}

// NewFileCache Create new file cache with no config.
// the level and expiry need set in method StartAndGC as config string.
func NewFileCache() Cache {
// return &FileCache{CachePath:FileCachePath, FileSuffix:FileCacheFileSuffix}
return &FileCache{}
}

// StartAndGC will start and begin gc for file cache.
// the config need to be like {CachePath:"/cache","FileSuffix":".bin","DirectoryLevel":2,"EmbedExpiry":0}
func (fc *FileCache) StartAndGC(config string) error {

var cfg map[string]string
json.Unmarshal([]byte(config), &cfg)
if _, ok := cfg["CachePath"]; !ok {
cfg["CachePath"] = FileCachePath
}
if _, ok := cfg["FileSuffix"]; !ok {
cfg["FileSuffix"] = FileCacheFileSuffix
}
if _, ok := cfg["DirectoryLevel"]; !ok {
cfg["DirectoryLevel"] = strconv.Itoa(FileCacheDirectoryLevel)
}
if _, ok := cfg["EmbedExpiry"]; !ok {
cfg["EmbedExpiry"] = strconv.FormatInt(int64(FileCacheEmbedExpiry.Seconds()), 10)
}
fc.CachePath = cfg["CachePath"]
fc.FileSuffix = cfg["FileSuffix"]
fc.DirectoryLevel, _ = strconv.Atoi(cfg["DirectoryLevel"])
fc.EmbedExpiry, _ = strconv.Atoi(cfg["EmbedExpiry"])

fc.Init()
return nil
}

// Init will make new dir for file cache if not exist.
func (fc *FileCache) Init() {
if ok, _ := exists(fc.CachePath); !ok { // todo : error handle
_ = os.MkdirAll(fc.CachePath, os.ModePerm) // todo : error handle
}
}

// get cached file name. it's md5 encoded.
func (fc *FileCache) getCacheFileName(key string) string {
m := md5.New()
io.WriteString(m, key)
keyMd5 := hex.EncodeToString(m.Sum(nil))
cachePath := fc.CachePath
switch fc.DirectoryLevel {
case 2:
cachePath = filepath.Join(cachePath, keyMd5[0:2], keyMd5[2:4])
case 1:
cachePath = filepath.Join(cachePath, keyMd5[0:2])
}

if ok, _ := exists(cachePath); !ok { // todo : error handle
_ = os.MkdirAll(cachePath, os.ModePerm) // todo : error handle
}

return filepath.Join(cachePath, fmt.Sprintf("%s%s", keyMd5, fc.FileSuffix))
}

// Get value from file cache.
// if non-exist or expired, return empty string.
func (fc *FileCache) Get(key string) interface{} {
fileData, err := FileGetContents(fc.getCacheFileName(key))
if err != nil {
return ""
}
var to FileCacheItem
GobDecode(fileData, &to)
if to.Expired.Before(time.Now()) {
return ""
}
return to.Data
}

// GetMulti gets values from file cache.
// if non-exist or expired, return empty string.
func (fc *FileCache) GetMulti(keys []string) []interface{} {
var rc []interface{}
for _, key := range keys {
rc = append(rc, fc.Get(key))
}
return rc
}

// Put value into file cache.
// timeout means how long to keep this file, unit of ms.
// if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever.
func (fc *FileCache) Put(key string, val interface{}, timeout time.Duration) error {
gob.Register(val)

item := FileCacheItem{Data: val}
if timeout == FileCacheEmbedExpiry {
item.Expired = time.Now().Add((86400 * 365 * 10) * time.Second) // ten years
} else {
item.Expired = time.Now().Add(timeout)
}
item.LastAccess = time.Now()
data, err := GobEncode(item)
if err != nil {
return err
}
return FilePutContents(fc.getCacheFileName(key), data)
}

// Delete file cache value.
func (fc *FileCache) Delete(key string) error {
filename := fc.getCacheFileName(key)
if ok, _ := exists(filename); ok {
return os.Remove(filename)
}
return nil
}

// Incr will increase cached int value.
// fc value is saving forever unless Delete.
func (fc *FileCache) Incr(key string) error {
data := fc.Get(key)
var incr int
if reflect.TypeOf(data).Name() != "int" {
incr = 0
} else {
incr = data.(int) + 1
}
fc.Put(key, incr, FileCacheEmbedExpiry)
return nil
}

// Decr will decrease cached int value.
func (fc *FileCache) Decr(key string) error {
data := fc.Get(key)
var decr int
if reflect.TypeOf(data).Name() != "int" || data.(int)-1 <= 0 {
decr = 0
} else {
decr = data.(int) - 1
}
fc.Put(key, decr, FileCacheEmbedExpiry)
return nil
}

// IsExist check value is exist.
func (fc *FileCache) IsExist(key string) bool {
ret, _ := exists(fc.getCacheFileName(key))
return ret
}

// ClearAll will clean cached files.
// not implemented.
func (fc *FileCache) ClearAll() error {
return nil
}

// check file exist.
func exists(path string) (bool, error) {
_, err := os.Stat(path)
if err == nil {
return true, nil
}
if os.IsNotExist(err) {
return false, nil
}
return false, err
}

// FileGetContents Get bytes to file.
// if non-exist, create this file.
func FileGetContents(filename string) (data []byte, e error) {
return ioutil.ReadFile(filename)
}

// FilePutContents Put bytes to file.
// if non-exist, create this file.
func FilePutContents(filename string, content []byte) error {
return ioutil.WriteFile(filename, content, os.ModePerm)
}

// GobEncode Gob encodes file cache item.
func GobEncode(data interface{}) ([]byte, error) {
buf := bytes.NewBuffer(nil)
enc := gob.NewEncoder(buf)
err := enc.Encode(data)
if err != nil {
return nil, err
}
return buf.Bytes(), err
}

// GobDecode Gob decodes file cache item.
func GobDecode(data []byte, to *FileCacheItem) error {
buf := bytes.NewBuffer(data)
dec := gob.NewDecoder(buf)
return dec.Decode(&to)
}

func init() {
Register("file", NewFileCache)
}

+ 239
- 0
app/utils/cachesecond/cache/memory.go ファイルの表示

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

import (
"encoding/json"
"errors"
"sync"
"time"
)

var (
// DefaultEvery means the clock time of recycling the expired cache items in memory.
DefaultEvery = 60 // 1 minute
)

// MemoryItem store memory cache item.
type MemoryItem struct {
val interface{}
createdTime time.Time
lifespan time.Duration
}

func (mi *MemoryItem) isExpire() bool {
// 0 means forever
if mi.lifespan == 0 {
return false
}
return time.Now().Sub(mi.createdTime) > mi.lifespan
}

// MemoryCache is Memory cache adapter.
// it contains a RW locker for safe map storage.
type MemoryCache struct {
sync.RWMutex
dur time.Duration
items map[string]*MemoryItem
Every int // run an expiration check Every clock time
}

// NewMemoryCache returns a new MemoryCache.
func NewMemoryCache() Cache {
cache := MemoryCache{items: make(map[string]*MemoryItem)}
return &cache
}

// Get cache from memory.
// if non-existed or expired, return nil.
func (bc *MemoryCache) Get(name string) interface{} {
bc.RLock()
defer bc.RUnlock()
if itm, ok := bc.items[name]; ok {
if itm.isExpire() {
return nil
}
return itm.val
}
return nil
}

// GetMulti gets caches from memory.
// if non-existed or expired, return nil.
func (bc *MemoryCache) GetMulti(names []string) []interface{} {
var rc []interface{}
for _, name := range names {
rc = append(rc, bc.Get(name))
}
return rc
}

// Put cache to memory.
// if lifespan is 0, it will be forever till restart.
func (bc *MemoryCache) Put(name string, value interface{}, lifespan time.Duration) error {
bc.Lock()
defer bc.Unlock()
bc.items[name] = &MemoryItem{
val: value,
createdTime: time.Now(),
lifespan: lifespan,
}
return nil
}

// Delete cache in memory.
func (bc *MemoryCache) Delete(name string) error {
bc.Lock()
defer bc.Unlock()
if _, ok := bc.items[name]; !ok {
return errors.New("key not exist")
}
delete(bc.items, name)
if _, ok := bc.items[name]; ok {
return errors.New("delete key error")
}
return nil
}

// Incr increase cache counter in memory.
// it supports int,int32,int64,uint,uint32,uint64.
func (bc *MemoryCache) Incr(key string) error {
bc.RLock()
defer bc.RUnlock()
itm, ok := bc.items[key]
if !ok {
return errors.New("key not exist")
}
switch itm.val.(type) {
case int:
itm.val = itm.val.(int) + 1
case int32:
itm.val = itm.val.(int32) + 1
case int64:
itm.val = itm.val.(int64) + 1
case uint:
itm.val = itm.val.(uint) + 1
case uint32:
itm.val = itm.val.(uint32) + 1
case uint64:
itm.val = itm.val.(uint64) + 1
default:
return errors.New("item val is not (u)int (u)int32 (u)int64")
}
return nil
}

// Decr decrease counter in memory.
func (bc *MemoryCache) Decr(key string) error {
bc.RLock()
defer bc.RUnlock()
itm, ok := bc.items[key]
if !ok {
return errors.New("key not exist")
}
switch itm.val.(type) {
case int:
itm.val = itm.val.(int) - 1
case int64:
itm.val = itm.val.(int64) - 1
case int32:
itm.val = itm.val.(int32) - 1
case uint:
if itm.val.(uint) > 0 {
itm.val = itm.val.(uint) - 1
} else {
return errors.New("item val is less than 0")
}
case uint32:
if itm.val.(uint32) > 0 {
itm.val = itm.val.(uint32) - 1
} else {
return errors.New("item val is less than 0")
}
case uint64:
if itm.val.(uint64) > 0 {
itm.val = itm.val.(uint64) - 1
} else {
return errors.New("item val is less than 0")
}
default:
return errors.New("item val is not int int64 int32")
}
return nil
}

// IsExist check cache exist in memory.
func (bc *MemoryCache) IsExist(name string) bool {
bc.RLock()
defer bc.RUnlock()
if v, ok := bc.items[name]; ok {
return !v.isExpire()
}
return false
}

// ClearAll will delete all cache in memory.
func (bc *MemoryCache) ClearAll() error {
bc.Lock()
defer bc.Unlock()
bc.items = make(map[string]*MemoryItem)
return nil
}

// StartAndGC start memory cache. it will check expiration in every clock time.
func (bc *MemoryCache) StartAndGC(config string) error {
var cf map[string]int
json.Unmarshal([]byte(config), &cf)
if _, ok := cf["interval"]; !ok {
cf = make(map[string]int)
cf["interval"] = DefaultEvery
}
dur := time.Duration(cf["interval"]) * time.Second
bc.Every = cf["interval"]
bc.dur = dur
go bc.vacuum()
return nil
}

// check expiration.
func (bc *MemoryCache) vacuum() {
bc.RLock()
every := bc.Every
bc.RUnlock()

if every < 1 {
return
}
for {
<-time.After(bc.dur)
if bc.items == nil {
return
}
if keys := bc.expiredKeys(); len(keys) != 0 {
bc.clearItems(keys)
}
}
}

// expiredKeys returns key list which are expired.
func (bc *MemoryCache) expiredKeys() (keys []string) {
bc.RLock()
defer bc.RUnlock()
for key, itm := range bc.items {
if itm.isExpire() {
keys = append(keys, key)
}
}
return
}

// clearItems removes all the items which key in keys.
func (bc *MemoryCache) clearItems(keys []string) {
bc.Lock()
defer bc.Unlock()
for _, key := range keys {
delete(bc.items, key)
}
}

func init() {
Register("memory", NewMemoryCache)
}

+ 406
- 0
app/utils/cachesecond/redis.go ファイルの表示

@@ -0,0 +1,406 @@
package cachesecond

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

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

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

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

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

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

var pool *redigo.Pool
var conf *Config

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 622
- 0
app/utils/cachesecond/redis_cluster.go ファイルの表示

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

import (
"strconv"
"time"

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

var pools *redis.ClusterClient

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

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

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

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

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

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

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

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

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

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

+ 324
- 0
app/utils/cachesecond/redis_pool.go ファイルの表示

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

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

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

type RedisPool struct {
*redigo.Pool
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

return newCursor, items, nil
}

+ 617
- 0
app/utils/cachesecond/redis_pool_cluster.go ファイルの表示

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

import (
"strconv"
"time"

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

type RedisClusterPool struct {
client *redis.ClusterClient
}

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

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

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

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

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

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

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

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

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

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

+ 20
- 0
app/utils/json.go ファイルの表示

@@ -3,6 +3,7 @@ package utils
import (
"bytes"
"encoding/json"
"regexp"
)

func JsonMarshal(interface{}) {
@@ -15,3 +16,22 @@ func JsonDecode(data []byte, v interface{}) error {
d.UseNumber()
return d.Decode(v)
}

// json字符串驼峰命名格式 转为 下划线命名格式
// c :json字符串
func MarshalJSONCamelCase2JsonSnakeCase(c string) []byte {
// Regexp definitions
var keyMatchRegex = regexp.MustCompile(`\"(\w+)\":`)
var wordBarrierRegex = regexp.MustCompile(`(\w)([A-Z])`)
marshalled := []byte(c)
converted := keyMatchRegex.ReplaceAllFunc(
marshalled,
func(match []byte) []byte {
return bytes.ToLower(wordBarrierRegex.ReplaceAll(
match,
[]byte(`${1}_${2}`),
))
},
)
return converted
}

+ 0
- 172
consume/zhios_user_visit_ip_address_consume.go ファイルの表示

@@ -1,172 +0,0 @@
package consume

import (
"applet/app/db"
"applet/app/db/model"
"applet/app/utils"
"applet/app/utils/cache"
"applet/app/utils/logx"
"applet/consume/md"
"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit"
"encoding/json"
"errors"
"fmt"
"github.com/cc14514/go-geoip2"
geoip2db "github.com/cc14514/go-geoip2-db"
"github.com/streadway/amqp"
"net"
"strings"
"time"
)

var data []*model.MasterAreaVisitsFlows

func ZhiOsUserVisitIpAddressConsume(queue md.MqQueue) {
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>ZhiOsUserVisitIpAddressConsume<<<<<<<<<<<<<<<<<<<<<<<")
ch, err := rabbit.Cfg.Pool.GetChannel()
if err != nil {
logx.Error(err)
return
}
geoIp2db, _ := geoip2db.NewGeoipDbByStatik()
defer geoIp2db.Close()

defer ch.Release()
//1、将自己绑定到交换机上
ch.Bind(queue.Name, queue.ExchangeName, queue.RoutKey)
//2、取出数据进行消费
ch.Qos(100)
delivery := ch.Consume(queue.Name, false)

var res amqp.Delivery
var ok bool
for {
res, ok = <-delivery
if ok == true {
fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
err = handleUserVisitIpAddress(res.Body, geoIp2db)
//_ = res.Reject(false)
_ = res.Ack(true)
if len(data) >= 100 {
db.BatchAddMasterAreaVisitsFlows(db.DataDb, data)
data = []*model.MasterAreaVisitsFlows{}
}
} else {
panic(errors.New("error getting message"))
}
}
fmt.Println("get msg done")
}

func handleUserVisitIpAddress(msg []byte, geoIp2db *geoip2.DBReader) error {
now := time.Now()
today := now.Format("2006-01-02")
var tmpString string
err := json.Unmarshal(msg, &tmpString)
if err != nil {
fmt.Println(err.Error())
return err
}
var msgStruct md.ZhiOsUserVisitIpAddressMessage
err = json.Unmarshal([]byte(tmpString), &msgStruct)
if err != nil {
fmt.Println(err.Error())
return err
}

if msgStruct.MasterId == "" {
cacheKeyForUrl := fmt.Sprintf(md.ZhiOsMasterIdForUrlHashMapCacheKey)
get, _ := cache.HGetString(cacheKeyForUrl, msgStruct.Url)
if get == "" {
msgStruct.MasterId = GetWebSiteDomainMasterId(msgStruct.Url)
utils.FilePutContents("GetWebSiteDomainMasterId", utils.SerializeStr(msgStruct))
cache.HSet(cacheKeyForUrl, msgStruct.Url, msgStruct.MasterId)
cache.Expire(cacheKeyForUrl, md.ZhiOsUserVisitIpAddressHashMapCacheTime)
} else {
msgStruct.MasterId = get
}
}

//1、判断ip是否已统计
cacheKey := fmt.Sprintf(md.ZhiOsUserVisitIpAddressHashMapCacheKey, msgStruct.MasterId, today)
//get, _ := cache.HGetString(cacheKey, msgStruct.Ip)
//if get == "" {
if true {
//2、分析ip归属地
countryName, provinceId, cityId, provinceName, cityName := getIpAddress(geoIp2db, msgStruct)
if provinceId != "" || cityId != "" || countryName != "" || provinceName != "" || cityName != "" {
//3、插入`master_area_visits_flows` 表
if provinceName == "" {
provinceName = msgStruct.Province
}
if cityName == "" {
cityName = msgStruct.City
}

data = append(data, &model.MasterAreaVisitsFlows{
Ip: msgStruct.Ip,
MasterId: utils.StrToInt(msgStruct.MasterId),
Date: today,
CountryName: countryName,
ProvinceName: provinceName,
ProvinceId: provinceId,
CityName: cityName,
CityId: cityId,
Pvd: msgStruct.Pvd,
CreateAt: now,
UpdateAt: now,
})
//db.MasterAreaVisitsFlowsInsert(db.DataDb, )
}
//4、加入到缓存map中
cache.HSet(cacheKey, msgStruct.Ip, msgStruct.MasterId)
cache.Expire(cacheKey, md.ZhiOsUserVisitIpAddressHashMapCacheTime)
}
return nil
}

func getIpAddress(geoIp2db *geoip2.DBReader, message md.ZhiOsUserVisitIpAddressMessage) (countryName, provinceId, cityId, provinceName, cityName string) {
record, _ := geoIp2db.City(net.ParseIP(message.Ip))
if record.Country.Names != nil && record.Subdivisions != nil && record.City.Names != nil {
message.Country = record.Country.Names["zh-CN"]
message.Province = record.Subdivisions[0].Names["zh-CN"]
message.City = record.City.Names["zh-CN"]
}

countryName = message.Country
if countryName == "中国" && message.Province != "" {
if message.Province == "闽" {
message.Province = "福建"
}
province, err := db.ProvinceGetOneByName(message.Province)
if err != nil {
return "", "", "", "", ""
}
provinceId = province.Id
provinceName = province.Name

if message.City != "" {
city, err := db.CityGetOneByName(message.City)
if err != nil {
return "", "", "", "", ""
}
cityId = city.Id
cityName = city.Name
}
}
return
}

// 获取指定类型的域名对应的masterId:admin、wap、api
func GetWebSiteDomainMasterId(host string) string {
obj := new(model.UserAppDomain)
has, err := db.Db.Where("domain=?", host).Get(obj)
if err != nil || !has {
hostList := strings.Split(host, ":")
has, err = db.Db.Where("domain=?", hostList[0]).Get(obj)
if err != nil || !has {
return ""
}
}
return utils.AnyToString(obj.Uuid)
}

+ 17
- 4
go.mod ファイルの表示

@@ -4,6 +4,7 @@ go 1.18

require (
code.fnuoos.com/go_rely_warehouse/zyos_go_condition_statistics.git v1.1.2-0.20240222023917-c31b53f7e8cb
code.fnuoos.com/go_rely_warehouse/zyos_go_coupon.git v1.1.2
code.fnuoos.com/go_rely_warehouse/zyos_go_es.git v1.0.0
code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git v0.0.4
code.fnuoos.com/go_rely_warehouse/zyos_go_order_relate_rule.git v1.9.10-0.20240428041015-bcc1e79f0d28
@@ -15,6 +16,7 @@ require (
github.com/cc14514/go-geoip2 v0.0.0-20190105051856-0a1854480a11
github.com/cc14514/go-geoip2-db v0.0.0-20190106063142-7b6408a9812a
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/forgoer/openssl v1.2.1
github.com/gin-contrib/sessions v1.0.0
github.com/gin-gonic/gin v1.9.1
@@ -45,13 +47,17 @@ require (
)

require (
code.fnuoos.com/go_rely_warehouse/zyos_go_coupon.git v1.1.2 // indirect
code.fnuoos.com/go_rely_warehouse/zyos_go_day_luck_draw.git v1.2.1 // indirect
code.fnuoos.com/go_rely_warehouse/zyos_go_jg_push.git v1.0.5 // indirect
code.fnuoos.com/go_rely_warehouse/zyos_go_o2o_business.git v1.0.9 // indirect
github.com/KyleBanks/depth v1.2.1 // indirect
github.com/PuerkitoBio/goquery v1.9.2 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/andybalholm/cascadia v1.3.2 // indirect
github.com/antchfx/htmlquery v1.3.1 // indirect
github.com/antchfx/xmlquery v1.4.0 // indirect
github.com/antchfx/xpath v1.3.0 // indirect
github.com/bitly/go-simplejson v0.5.0 // indirect
github.com/bytedance/sonic v1.11.3 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
@@ -62,13 +68,17 @@ require (
github.com/go-openapi/jsonreference v0.19.5 // indirect
github.com/go-openapi/spec v0.20.3 // indirect
github.com/go-openapi/swag v0.19.15 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/gocolly/colly v1.2.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gorilla/context v1.1.2 // indirect
github.com/gorilla/securecookie v1.1.2 // indirect
github.com/gorilla/sessions v1.2.2 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/kennygrant/sanitize v1.2.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
@@ -81,7 +91,9 @@ require (
github.com/pelletier/go-toml/v2 v2.2.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rakyll/statik v0.1.7 // indirect
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/temoto/robotstxt v1.1.2 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
@@ -89,14 +101,15 @@ require (
go.uber.org/atomic v1.7.0 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/arch v0.7.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/crypto v0.22.0 // indirect
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect
golang.org/x/net v0.22.0 // indirect
golang.org/x/net v0.24.0 // indirect
golang.org/x/sync v0.6.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/sys v0.19.0 // indirect
golang.org/x/text v0.14.0 // indirect
golang.org/x/tools v0.6.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/appengine v1.4.0 // indirect
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
honnef.co/go/tools v0.0.1-2020.1.4 // indirect


+ 0
- 6
main.go ファイルの表示

@@ -23,12 +23,6 @@ func init() {
if err := db.InitDB(cfg.DB); err != nil { //主数据库初始化
panic(err)
}
if err := db.InitDataDB(cfg.DataDB); err != nil { //数据大屏本身库初始化
panic(err)
}
if err := db.InitImDB(cfg.ImDB); err != nil { //im本身库初始化
panic(err)
}
channel := make(chan int, 0) //开辟管道,缓冲为
go db.InitDBs(channel)
<-channel


読み込み中…
キャンセル
保存