@@ -12,7 +12,7 @@ | |||
- md 结构体 | |||
#### 介绍 | |||
基于gin的接口小程序 | |||
蛋蛋星球后台管理项目 | |||
#### 软件架构 | |||
@@ -39,10 +39,23 @@ | |||
## swagger | |||
``` | |||
// 参考:https://segmentfault.com/a/1190000013808421 | |||
// 安装命令行 | |||
> 参考:https://segmentfault.com/a/1190000013808421 | |||
> swagger 命令行工具 | |||
go get -u github.com/swaggo/swag/cmd/swag | |||
// 生成 | |||
//go版本1.16之前使用该命令 | |||
go install github.com/swaggo/swag/cmd/swag | |||
//go版本1.16版本以及之后的版本使用该命令 | |||
go install github.com/swaggo/swag/cmd/swag@latest | |||
> swagger 依赖 | |||
go get "github.com/swaggo/files" | |||
go get "github.com/swaggo/gin-swagger" | |||
> 生成 | |||
swag init | |||
``` |
@@ -5,51 +5,41 @@ import ( | |||
) | |||
type Config struct { | |||
Debug bool `yaml:"debug"` | |||
Prd bool `yaml:"prd"` | |||
CurlDebug bool `yaml:"curldebug"` | |||
SrvAddr string `yaml:"srv_addr"` | |||
RedisAddr string `yaml:"redis_addr"` | |||
DB DBCfg `yaml:"db"` | |||
Log LogCfg `yaml:"log"` | |||
ArkID ArkIDCfg `yaml:"arkid"` | |||
Admin AdminCfg `yaml:"admin"` | |||
Official OfficialCfg `yaml:"official"` | |||
WxappletFilepath WxappletFilepathCfg `yaml:"wxapplet_filepath"` | |||
Local bool | |||
AppComm AppCommCfg `yaml:"app_comm"` | |||
Debug bool `yaml:"debug"` | |||
Prd bool `yaml:"prd"` | |||
CurlDebug bool `yaml:"curldebug"` | |||
SrvAddr string `yaml:"srv_addr"` | |||
RedisAddr string `yaml:"redis_addr"` | |||
RedisPassword string `yaml:"redis_password"` | |||
DB DBCfg `yaml:"db"` | |||
Log LogCfg `yaml:"log"` | |||
ImBusinessRpc ImBusinessRpcCfg `yaml:"im_business_rpc"` | |||
ImLogicRpc ImLogicRpcCfg `yaml:"im_logic_rpc"` | |||
Local bool | |||
MQ MQCfg `yaml:"mq"` | |||
} | |||
// 公共模块 | |||
type AppCommCfg struct { | |||
URL string `yaml:"url"` | |||
type ImBusinessRpcCfg struct { | |||
URL string `yaml:"url"` | |||
PORT string `yaml:"port"` | |||
} | |||
// OfficialCfg is 官网 | |||
type OfficialCfg struct { | |||
URL string `yaml:"url"` | |||
} | |||
type WxappletFilepathCfg struct { | |||
URL string `yaml:"url"` | |||
type ImLogicRpcCfg struct { | |||
URL string `yaml:"url"` | |||
PORT string `yaml:"port"` | |||
} | |||
// AdminCfg is 后台接口调用需要 | |||
type AdminCfg struct { | |||
URL string `yaml:"url"` | |||
IURL string `yaml:"iurl"` | |||
AesKey string `yaml:"api_aes_key"` | |||
AesIV string `yaml:"api_aes_iv"` | |||
Host string `yaml:"host"` | |||
type AppCommCfg struct { | |||
OuterURL string `yaml:"outer_url"` // 本模块外部地址 | |||
} | |||
type ArkIDCfg struct { | |||
Admin string `yaml:"admin"` | |||
AdminPassword string `yaml:"admin_password"` | |||
Url string `yaml:"url` | |||
Url string `yaml:"url"` | |||
} | |||
//数据库配置结构体 | |||
// 数据库配置结构体 | |||
type DBCfg struct { | |||
Host string `yaml:"host"` //ip及端口 | |||
Name string `yaml:"name"` //库名 | |||
@@ -62,7 +52,7 @@ type DBCfg struct { | |||
Path string `yaml:"path"` //日志文件存放路径 | |||
} | |||
//日志配置结构体 | |||
// 日志配置结构体 | |||
type LogCfg struct { | |||
AppName string `yaml:"app_name" ` | |||
Level string `yaml:"level"` | |||
@@ -76,3 +66,10 @@ type LogCfg struct { | |||
FileMaxSize int `yaml:"file_max_size"` | |||
FileMaxAge int `yaml:"file_max_age"` | |||
} | |||
type MQCfg struct { | |||
Host string `yaml:"host"` | |||
Port string `yaml:"port"` | |||
User string `yaml:"user"` | |||
Pwd string `yaml:"pwd"` | |||
} |
@@ -7,24 +7,20 @@ import ( | |||
"gopkg.in/yaml.v2" | |||
) | |||
//配置文件数据,全局变量 | |||
// 配置文件数据,全局变量 | |||
var ( | |||
Debug bool | |||
Prd bool | |||
CurlDebug bool | |||
SrvAddr string | |||
RedisAddr string | |||
DB *DBCfg | |||
Log *LogCfg | |||
ArkID *ArkIDCfg | |||
Admin *AdminCfg | |||
Official *OfficialCfg | |||
WxappletFilepath *WxappletFilepathCfg | |||
Local bool | |||
AppComm *AppCommCfg | |||
Debug bool | |||
Prd bool | |||
SrvAddr string | |||
SmartCanteenPay string | |||
RedisAddr string | |||
RedisPassword string | |||
DB *DBCfg | |||
MQ *MQCfg | |||
Log *LogCfg | |||
) | |||
//初始化配置文件,将cfg.yml读入到内存 | |||
// 初始化配置文件,将cfg.yml读入到内存 | |||
func InitCfg() { | |||
//用指定的名称、默认值、使用信息注册一个string类型flag。 | |||
path := flag.String("c", "etc/cfg.yml", "config file") | |||
@@ -46,15 +42,10 @@ func InitCfg() { | |||
//数据读入内存 | |||
Prd = conf.Prd | |||
Debug = conf.Debug | |||
Local = conf.Local | |||
CurlDebug = conf.CurlDebug | |||
DB = &conf.DB | |||
Log = &conf.Log | |||
ArkID = &conf.ArkID | |||
RedisAddr = conf.RedisAddr | |||
RedisPassword = conf.RedisPassword | |||
SrvAddr = conf.SrvAddr | |||
Admin = &conf.Admin | |||
Official = &conf.Official | |||
WxappletFilepath = &conf.WxappletFilepath | |||
AppComm = &conf.AppComm | |||
MQ = &conf.MQ | |||
} |
@@ -0,0 +1,28 @@ | |||
package cfg | |||
import ( | |||
"code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git/rabbit" | |||
"encoding/json" | |||
"os" | |||
"strings" | |||
"time" | |||
) | |||
func InitMq() { | |||
data, _ := json.Marshal(MQ) | |||
filePutContents("init_rabbit_mq", string(data)) | |||
err := rabbit.Init(MQ.Host, MQ.Port, MQ.User, MQ.Pwd) | |||
if err != nil { | |||
filePutContents("init_rabbit_mq", err.Error()) | |||
return | |||
} | |||
} | |||
func filePutContents(fileName string, content string) { | |||
fd, _ := os.OpenFile("./tmp/"+fileName+".log", os.O_RDWR|os.O_CREATE|os.O_APPEND, 0644) | |||
fd_time := time.Now().Format("2006-01-02 15:04:05") | |||
fd_content := strings.Join([]string{"[", fd_time, "] ", content, "\n"}, "") | |||
buf := []byte(fd_content) | |||
fd.Write(buf) | |||
fd.Close() | |||
} |
@@ -28,10 +28,7 @@ func InitTaskCfg() { | |||
Debug = conf.Debug | |||
DB = &conf.DB | |||
Log = &conf.Log | |||
Admin = &conf.Admin | |||
RedisAddr = conf.RedisAddr | |||
Local = conf.Local | |||
AppComm = &conf.AppComm | |||
} | |||
var MemCache mc.Cache | |||
@@ -1,104 +0,0 @@ | |||
package db | |||
import ( | |||
"fmt" | |||
"os" | |||
"time" | |||
"xorm.io/xorm" | |||
"xorm.io/xorm/log" | |||
"applet/app/cfg" | |||
"applet/app/db/model" | |||
"applet/app/utils/logx" | |||
) | |||
var DBs map[string]*xorm.Engine | |||
// 每个站长都要有自己的syscfg 缓存, 键是站长id,值是缓存名 | |||
// var SysCfgMapKey map[string]string | |||
func NewDB(c *cfg.DBCfg) (*xorm.Engine, error) { | |||
db, err := xorm.NewEngine("mysql", fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8mb4", c.User, c.Psw, c.Host, c.Name)) | |||
if err != nil { | |||
return nil, err | |||
} | |||
db.SetConnMaxLifetime(c.MaxLifetime * time.Second) | |||
db.SetMaxOpenConns(c.MaxOpenConns) | |||
db.SetMaxIdleConns(c.MaxIdleConns) | |||
err = db.Ping() | |||
if err != nil { | |||
return nil, err | |||
} | |||
if c.ShowLog { | |||
db.ShowSQL(true) | |||
db.Logger().SetLevel(log.LOG_DEBUG) | |||
f, err := os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777) | |||
if err != nil { | |||
os.RemoveAll(c.Path) | |||
if f, err = os.OpenFile(c.Path, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0777); err != nil { | |||
return nil, err | |||
} | |||
} | |||
logger := log.NewSimpleLogger(f) | |||
logger.ShowSQL(true) | |||
db.SetLogger(logger) | |||
} | |||
return db, nil | |||
} | |||
// InitDBs is 初始化多数据库 | |||
func InitDBs(ch chan int) { | |||
// 初始化多数据库 | |||
var tables *[]model.DbMapping | |||
InitMapDbs(cfg.DB, cfg.Prd) | |||
ch <- 1 | |||
// 每10s 查询一次模板数据库的db mapping 表,如果有新增数据库记录,则添加到 DBs中 | |||
ticker := time.NewTicker(time.Duration(time.Second * 120)) | |||
for range ticker.C { | |||
if cfg.Prd { | |||
tables = GetAllDatabasePrd() //默认获取全部 | |||
} else { | |||
tables = GetAllDatabaseDev() //默认获取全部 | |||
} | |||
if tables == nil { | |||
logx.Warn("no database tables data") | |||
continue | |||
} | |||
for _, item := range *tables { | |||
_, ok := DBs[item.DbMasterId] | |||
if !ok { | |||
// 不在db.DBs 则添加进去 | |||
dbCfg := cfg.DBCfg{ | |||
Name: item.DbName, | |||
ShowLog: cfg.DB.ShowLog, | |||
MaxLifetime: cfg.DB.MaxLifetime, | |||
MaxOpenConns: cfg.DB.MaxOpenConns, | |||
MaxIdleConns: cfg.DB.MaxIdleConns, | |||
Path: fmt.Sprintf(cfg.DB.Path, item.DbName), | |||
} | |||
if item.DbHost != "" && item.DbUsername != "" && item.DbPassword != "" { | |||
dbCfg.Host = item.DbHost | |||
dbCfg.User = item.DbUsername | |||
dbCfg.Psw = item.DbPassword | |||
} else { | |||
dbCfg.Host = cfg.DB.Host | |||
dbCfg.User = cfg.DB.User | |||
dbCfg.Psw = cfg.DB.Psw | |||
} | |||
e, err := NewDB(&dbCfg) | |||
if err != nil || e == nil { | |||
logx.Warnf("db engine can't create, please check config, params[host:%s, user:%s, psw: %s, name: %s], err: %v", dbCfg.Host, dbCfg.User, dbCfg.Psw, dbCfg.Name, err) | |||
} else { | |||
DBs[item.DbMasterId] = e | |||
} | |||
} | |||
// 如果 被禁用则删除 | |||
if item.DeletedAt == 1 { | |||
logx.Infof("%s have been removed", item.DbMasterId) | |||
delete(DBs, item.DbMasterId) | |||
} | |||
} | |||
} | |||
} |
@@ -1,194 +0,0 @@ | |||
package db | |||
import ( | |||
"errors" | |||
"fmt" | |||
"xorm.io/xorm" | |||
"applet/app/cfg" | |||
"applet/app/db/model" | |||
"applet/app/utils/logx" | |||
) | |||
func MapBaseExists() (bool, error) { | |||
return Db.IsTableExist("db_mapping") | |||
} | |||
func InitMapDbs(c *cfg.DBCfg, prd bool) { | |||
var tables *[]model.DbMapping | |||
exists, err := MapBaseExists() | |||
if !exists || err != nil { | |||
logx.Fatalf("db_mapping not exists : %v", err) | |||
} | |||
// tables := MapAllDatabases(debug) | |||
if prd { | |||
tables = GetAllDatabasePrd() //debug 获取生产 | |||
} else { | |||
tables = GetAllDatabaseDev() //debug 获取开发 | |||
} | |||
if tables == nil { | |||
logx.Fatal("no database tables data") | |||
} | |||
var e *xorm.Engine | |||
DBs = map[string]*xorm.Engine{} | |||
for _, v := range *tables { | |||
if v.DbName != "" && v.DeletedAt == 0 && v.DbName != c.Name { | |||
dbCfg := cfg.DBCfg{ | |||
Name: v.DbName, | |||
ShowLog: c.ShowLog, | |||
MaxLifetime: c.MaxLifetime, | |||
MaxOpenConns: c.MaxOpenConns, | |||
MaxIdleConns: c.MaxIdleConns, | |||
Path: fmt.Sprintf(c.Path, v.DbName), | |||
} | |||
if v.DbHost != "" && v.DbUsername != "" && v.DbPassword != "" { | |||
dbCfg.Host = v.DbHost | |||
dbCfg.User = v.DbUsername | |||
dbCfg.Psw = v.DbPassword | |||
} else { | |||
dbCfg.Host = c.Host | |||
dbCfg.User = c.User | |||
dbCfg.Psw = c.Psw | |||
} | |||
e, err = NewDB(&dbCfg) | |||
if err != nil || e == nil { | |||
logx.Warnf("db engine can't create, please check config, params[host:%s, user:%s, psw: %s, name: %s], err: %v", dbCfg.Host, dbCfg.User, dbCfg.Psw, dbCfg.Name, err) | |||
} else { | |||
DBs[v.DbMasterId] = e | |||
} | |||
} | |||
} | |||
} | |||
func MapAllDatabases(debug bool) *[]model.DbMapping { | |||
sql := "`db_name` != ?" | |||
if debug { | |||
sql = "`db_name` = ?" | |||
} | |||
var m []model.DbMapping | |||
if err := Db.Where(sql, cfg.DB.Name).Find(&m); err != nil || len(m) == 0 { | |||
logx.Warn(err) | |||
return nil | |||
} | |||
return &m | |||
} | |||
// GetAllDatabasePrd is 获取生成库 所有db 除了 deleted_at = 1 的 | |||
func GetAllDatabasePrd() *[]model.DbMapping { | |||
var m []model.DbMapping | |||
if err := Db.Where("deleted_at != ? AND is_dev = '0' ", 1).Find(&m); err != nil || len(m) == 0 { | |||
logx.Warn(err) | |||
return nil | |||
} | |||
return &m | |||
} | |||
// GetAllDatabaseDev is 获取开发库 所有db 除了 deleted_at = 1 的 | |||
func GetAllDatabaseDev() *[]model.DbMapping { | |||
var m []model.DbMapping | |||
var err error | |||
fmt.Println("cfg.Local is: ", cfg.Local) | |||
if cfg.Local { // 本地调试 加快速度 | |||
fmt.Println("notice:LOCAL TEST, only masterId:** 123456 ** available!") | |||
err = Db.Where("deleted_at != ? AND is_dev = '1' AND db_master_id=?", 1, 123456).Find(&m) | |||
} else { | |||
err = Db.Where("deleted_at != ? AND is_dev = '1' ", 1).Find(&m) | |||
} | |||
//err := Db.Where("deleted_at != ? AND is_dev = '1' and db_master_id='123456'", 1).Find(&m) | |||
if err != nil || len(m) == 0 { | |||
logx.Warn(err) | |||
return nil | |||
} | |||
return &m | |||
} | |||
//GetDatabaseByMasterID is 根据站长id 获取对应的的数据库信息 | |||
func GetDatabaseByMasterID(Db *xorm.Engine, id string) (*model.DbMapping, error) { | |||
var m model.DbMapping | |||
has, err := Db.Where("db_master_id=?", id).Get(&m) | |||
if !has { | |||
return nil, errors.New("Not Found DB data by " + id) | |||
} | |||
if err != nil { | |||
return nil, err | |||
} | |||
if m.DbHost == "" { | |||
m.DbHost = cfg.DB.Host | |||
m.DbUsername = cfg.DB.User | |||
m.DbPassword = cfg.DB.Psw | |||
} | |||
return &m, nil | |||
} | |||
//SessionGetDatabaseByMasterID is 根据站长id 获取对应的的数据库信息 | |||
func SessionGetDatabaseByMasterID(Db *xorm.Session, id string) (*model.DbMapping, error) { | |||
var m model.DbMapping | |||
has, err := Db.Where("db_master_id=?", id).Get(&m) | |||
if !has { | |||
return nil, errors.New("Not Found DB data by " + id) | |||
} | |||
if err != nil { | |||
return nil, err | |||
} | |||
if m.DbHost == "" { | |||
m.DbHost = cfg.DB.Host | |||
m.DbName = cfg.DB.Name | |||
m.DbUsername = cfg.DB.User | |||
m.DbPassword = cfg.DB.Psw | |||
} | |||
return &m, nil | |||
} | |||
// 获取自动任务队列 | |||
func MapCrontabCfg(eg *xorm.Engine) *[]model.SysCfg { | |||
var c []model.SysCfg | |||
// 数据库查询如果有下划线会认为是一个任意字符 | |||
if err := eg.Where("`key` LIKE 'mall_cron\\_%' AND val != ''").Cols("`key`,`val`").Find(&c); err != nil || len(c) == 0 { | |||
logx.Warn(err) | |||
return nil | |||
} | |||
return &c | |||
} | |||
// 获取官方域名 | |||
func GetOfficialDomainInfoByType(Db *xorm.Engine, masterId, key string) (string, error) { | |||
type SysCfg struct { | |||
K string | |||
V string | |||
Memo string | |||
} | |||
var domainBase SysCfg | |||
has, err := Db.Where("k=?", "domain_base").Get(&domainBase) | |||
if err != nil { | |||
return "", err | |||
} | |||
if has == false { | |||
return "", errors.New("can not find key by : domain_base") | |||
} | |||
if key == "wap" { | |||
return "h5." + masterId + "." + domainBase.V, nil | |||
} | |||
if key == "api" { | |||
var apiDomain SysCfg | |||
has, err = Db.Where("k=?", "domain_api_base").Get(&apiDomain) | |||
if err != nil { | |||
return "", err | |||
} | |||
if has == false { | |||
return "", errors.New("can not find key by : domain_api_base") | |||
} | |||
return apiDomain.V, nil | |||
} | |||
if key == "admin" { | |||
return "admin." + masterId + "." + domainBase.V, nil | |||
} | |||
// 默认返回H5的 | |||
return "h5." + masterId + "." + domainBase.V, nil | |||
} |
@@ -6,6 +6,16 @@ import ( | |||
"github.com/gin-gonic/gin" | |||
) | |||
// Demo | |||
// @Summary Demo测试 | |||
// @Tags Demo | |||
// @Description Demo样例测试 | |||
// @Accept json | |||
// @Produce json | |||
// @Param req body interface{} true "用户名密码" | |||
// @Success 200 {object} map[string]interface{} "token" | |||
// @Failure 400 {object} md.Response "具体错误" | |||
// @Router /api/demo [post] | |||
func Demo(c *gin.Context) { | |||
var args interface{} | |||
err := c.ShouldBindJSON(&args) | |||
@@ -0,0 +1,39 @@ | |||
package auth | |||
import ( | |||
"errors" | |||
"github.com/dgrijalva/jwt-go" | |||
"time" | |||
) | |||
// GenToken 生成JWT | |||
func GenToken(admId int, username string) (string, error) { | |||
// 创建一个我们自己的声明 | |||
c := JWTUser{ | |||
AdmId: admId, | |||
Username: username, | |||
StandardClaims: jwt.StandardClaims{ | |||
ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间 | |||
Issuer: "smart_canteen", // 签发人 | |||
}, | |||
} | |||
// 使用指定的签名方法创建签名对象 | |||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c) | |||
// 使用指定的secret签名并获得完整的编码后的字符串token | |||
return token.SignedString(Secret) | |||
} | |||
// ParseToken 解析JWT | |||
func ParseToken(tokenString string) (*JWTUser, error) { | |||
// 解析token | |||
token, err := jwt.ParseWithClaims(tokenString, &JWTUser{}, func(token *jwt.Token) (i interface{}, err error) { | |||
return Secret, nil | |||
}) | |||
if err != nil { | |||
return nil, err | |||
} | |||
if claims, ok := token.Claims.(*JWTUser); ok && token.Valid { // 校验token | |||
return claims, nil | |||
} | |||
return nil, errors.New("invalid token") | |||
} |
@@ -7,17 +7,13 @@ import ( | |||
) | |||
// TokenExpireDuration is jwt 过期时间 | |||
const TokenExpireDuration = time.Hour * 4380 | |||
const TokenExpireDuration = time.Hour * 24 | |||
var Secret = []byte("zyos") | |||
var Secret = []byte("smart_canteen_admin") | |||
// 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 | |||
AdmId int `json:"adm_id"` | |||
Username string `json:"username"` | |||
jwt.StandardClaims | |||
} |
@@ -2,9 +2,7 @@ package md | |||
// 缓存key统一管理, %s格式化为masterId | |||
const ( | |||
AppCfgCacheKey = "%s:cfg_cache:%s" // 占位符: masterId, key的第一个字母 | |||
UserFinValidUpdateLock = "%s:user_fin_valid_update_lock:%s" // 用户余额更新锁(能拿到锁才能更新余额) | |||
AppCfgCacheKey = "cfg_cache:%s" // 占位符: key的第一个字母 | |||
CfgCacheTime = 86400 | |||
) |
@@ -0,0 +1,7 @@ | |||
package md | |||
type Response struct { | |||
Code string `json:"code" example:"响应码"` | |||
Data interface{} `json:"data" ` //内容 | |||
Msg string `json:"msg" example:"具体错误原因"` | |||
} |
@@ -1,42 +0,0 @@ | |||
package md | |||
import ( | |||
"regexp" | |||
"xorm.io/xorm" | |||
) | |||
type DbInfo struct { | |||
User string | |||
Psw string | |||
Name string | |||
Host string | |||
} | |||
func SplitDbInfo(eg *xorm.Engine) *DbInfo { | |||
if eg == nil { | |||
return &DbInfo{ | |||
User: "nil", | |||
Psw: "nil", | |||
Host: "nil", | |||
Name: "nil", | |||
} | |||
} | |||
pattern := `(\w+):(.*)@tcp\(([\w\.\-\:\_]+)\)\/(\w+)` | |||
reg := regexp.MustCompile(pattern).FindStringSubmatch(eg.DataSourceName()) | |||
if len(reg) < 5 { | |||
return &DbInfo{ | |||
User: "unknown", | |||
Psw: "unknown", | |||
Host: "unknown", | |||
Name: "unknown", | |||
} | |||
} | |||
return &DbInfo{ | |||
User: reg[1], | |||
Psw: reg[2], | |||
Host: reg[3], | |||
Name: reg[4], | |||
} | |||
} |
@@ -1,72 +1,31 @@ | |||
package mw | |||
import ( | |||
"errors" | |||
"applet/app/db" | |||
"applet/app/e" | |||
"applet/app/lib/arkid" | |||
"applet/app/md" | |||
"applet/app/utils" | |||
"applet/app/svc" | |||
"errors" | |||
"github.com/gin-gonic/gin" | |||
) | |||
// 检查权限, 签名等等 | |||
// Auth 检查权限, 签名等等 | |||
func Auth(c *gin.Context) { | |||
for k, v := range c.Request.Header { | |||
c.Set(k, v[0]) | |||
} | |||
token, ok := c.Get("Token") | |||
if !ok { | |||
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("没有找到token")) | |||
return | |||
} | |||
if token == "" { | |||
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("token 不能为空")) | |||
return | |||
} | |||
tokenStr := utils.AnyToString(token) | |||
arkIdSdk := arkid.NewArkID() | |||
var err error | |||
signUser := &md.User{} | |||
arkIdUser := new(arkid.ArkIDUser) | |||
if err = arkIdSdk.SelectFunction("arkid_user_info"). | |||
WithArgs(arkid.RequestBody{Token: tokenStr}). | |||
Result(arkIdUser); err != nil { | |||
e.OutErr(c, e.ERR_TOKEN_AUTH, err) //token 不存在 | |||
return | |||
} | |||
if arkIdUser.Username == "" { | |||
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("Token error")) | |||
return | |||
} | |||
if err = arkIdSdk.SelectFunction("arkid_login"). | |||
WithArgs(arkid.RequestBody{Username: arkIdUser.Username, Password: utils.Md5(arkIdUser.Username)}). | |||
Result(arkIdUser); err != nil { | |||
e.OutErr(c, e.ERR_TOKEN_AUTH, err) | |||
return | |||
} | |||
signUser.Ark = arkIdUser | |||
if signUser.Ark == nil { | |||
e.OutErr(c, e.ERR_TOKEN_AUTH, errors.New("无效token")) | |||
return | |||
} | |||
signUser.Info, err = db.UserFindByArkidUserName(db.DBs[c.GetString("mid")], arkIdUser.Username) | |||
if err != nil { | |||
e.OutErr(c, e.ERR_TOKEN_AUTH, err) | |||
return | |||
} | |||
if signUser.Info == nil { | |||
e.OutErr(c, e.ERR_TOKEN_AUTH, errors.New("无效token")) | |||
return | |||
} | |||
signUser.Profile, err = db.UserProfileFindByArkID(db.DBs[c.GetString("mid")], utils.IntToStr(arkIdUser.UserID)) | |||
admin, err := svc.CheckUser(c) | |||
if err != nil { | |||
e.OutErr(c, e.ERR_TOKEN_AUTH, err) | |||
return | |||
} | |||
c.Set("user", signUser) | |||
var e1 e.E | |||
switch { | |||
case errors.As(err, &e1): | |||
e.OutErr(c, e1.Code, e1.Error()) | |||
return | |||
default: | |||
e.OutErr(c, e.ERR_UNAUTHORIZED, err.Error()) | |||
return | |||
} | |||
} | |||
if admin == nil { | |||
e.OutErr(c, e.ERR_NOT_AUTH, "当前管理员信息失效") | |||
return | |||
} | |||
// 将当前请求的username信息保存到请求的上下文c上 | |||
c.Set("admin", admin) | |||
c.Next() | |||
} |
@@ -1,96 +0,0 @@ | |||
package mw | |||
import ( | |||
"applet/app/db" | |||
"applet/app/e" | |||
"applet/app/md" | |||
"applet/app/utils" | |||
"applet/app/utils/cache" | |||
"applet/app/utils/logx" | |||
"errors" | |||
"fmt" | |||
"strings" | |||
"github.com/gin-gonic/gin" | |||
) | |||
// AuthJWT is jwt middleware | |||
func AuthJWT(c *gin.Context) { | |||
authHeader := c.Request.Header.Get("Authorization") | |||
if authHeader == "" { | |||
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("token 不能为空")) | |||
return | |||
} | |||
// 按空格分割 | |||
parts := strings.SplitN(authHeader, " ", 2) | |||
if !(len(parts) == 2 && parts[0] == "Bearer") { | |||
e.OutErr(c, e.ERR_TOKEN_FORMAT, errors.New("token 格式不对")) | |||
return | |||
} | |||
// parts[1]是token | |||
mc, err := utils.ParseToken(parts[1]) | |||
if err != nil { | |||
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("token 过期或无效")) | |||
return | |||
} | |||
//fmt.Println(mc.UID) | |||
// 获取user | |||
u, err := db.UserFindByID(db.DBs[c.GetString("mid")], mc.UID) | |||
if err != nil { | |||
e.OutErr(c, e.ERR_DB_ORM, err) | |||
return | |||
} | |||
if u == nil { | |||
e.OutErr(c, e.ERR_UNAUTHORIZED, errors.New("token 过期或无效")) | |||
return | |||
} | |||
// 检验账号是否未激活或被冻结 | |||
switch u.State { | |||
case 0: | |||
e.OutErr(c, e.ERR_USER_NO_ACTIVE) | |||
return | |||
case 2: | |||
e.OutErr(c, e.ERR_USER_IS_BAN) | |||
return | |||
} | |||
// 校验是否和缓存的token一致,只能有一个token 是真实有效 | |||
key := fmt.Sprintf("%s:token:%s", c.GetString("mid"), u.Username) | |||
//fmt.Println(key) | |||
cjwt, err := cache.GetString(key) | |||
//fmt.Println(cjwt) | |||
if err != nil { | |||
logx.Warn(err) | |||
goto NOCACHE | |||
} | |||
if parts[1] != cjwt { | |||
e.OutErr(c, e.ERR_TOKEN_AUTH, errors.New("token expired")) | |||
return | |||
} | |||
NOCACHE: | |||
// 获取user profile | |||
up, err := db.UserProfileFindByID(db.DBs[c.GetString("mid")], mc.UID) | |||
if err != nil { | |||
e.OutErr(c, e.ERR_DB_ORM, err) | |||
return | |||
} | |||
// 获取user 等级 | |||
ul, err := db.UserLevelByID(db.DBs[c.GetString("mid")], u.Level) | |||
if err != nil { | |||
e.OutErr(c, e.ERR_DB_ORM, err) | |||
return | |||
} | |||
user := &md.User{ | |||
Info: u, | |||
Profile: up, | |||
Level: ul, | |||
} | |||
// 将当前请求的username信息保存到请求的上下文c上 | |||
c.Set("user", user) | |||
// 异步处理 有效会员和新会员 | |||
c.Next() // 后续的处理函数可以用过c.Get("user")来获取当前请求的用户信息 | |||
} |
@@ -1,30 +0,0 @@ | |||
package mw | |||
import ( | |||
"errors" | |||
"net/http" | |||
"strconv" | |||
"github.com/afex/hystrix-go/hystrix" | |||
"github.com/gin-gonic/gin" | |||
) | |||
// 熔断器, 此组件需要在gin.Recovery中间之前进行调用, 否则可能会导致panic时候, 无法recovery, 正确顺序如下 | |||
//r.Use(BreakerWrapper) | |||
//r.Use(gin.Recovery()) | |||
func Breaker(c *gin.Context) { | |||
name := c.Request.Method + "-" + c.Request.RequestURI | |||
hystrix.Do(name, func() error { | |||
c.Next() | |||
statusCode := c.Writer.Status() | |||
if statusCode >= http.StatusInternalServerError { | |||
return errors.New("status code " + strconv.Itoa(statusCode)) | |||
} | |||
return nil | |||
}, func(e error) error { | |||
if e == hystrix.ErrCircuitOpen { | |||
c.String(http.StatusAccepted, "请稍后重试") //todo 修改报错方法 | |||
} | |||
return e | |||
}) | |||
} |
@@ -1,17 +0,0 @@ | |||
package mw | |||
import ( | |||
"github.com/gin-gonic/gin" | |||
) | |||
// 修改传过来的头部字段 | |||
func ChangeHeader(c *gin.Context) { | |||
appvserison := c.GetHeader("AppVersionName") | |||
if appvserison == "" { | |||
appvserison = c.GetHeader("app_version_name") | |||
} | |||
if appvserison != "" { | |||
c.Request.Header.Add("app_version_name", appvserison) | |||
} | |||
c.Next() | |||
} |
@@ -1,34 +0,0 @@ | |||
package mw | |||
import ( | |||
"applet/app/e" | |||
"applet/app/utils" | |||
"bytes" | |||
"fmt" | |||
"github.com/gin-gonic/gin" | |||
"io/ioutil" | |||
) | |||
// CheckSign is 中间件 用来检查签名 | |||
func CheckSign(c *gin.Context) { | |||
bools := utils.SignCheck(c) | |||
if bools == false { | |||
e.OutErr(c, 400, e.NewErr(400, "签名校验错误,请求失败")) | |||
return | |||
} | |||
c.Next() | |||
} | |||
func CheckBody(c *gin.Context) { | |||
if utils.GetApiVersion(c) > 0 { | |||
body, _ := ioutil.ReadAll(c.Request.Body) | |||
fmt.Println(string(body)) | |||
if string(body) != "" { | |||
str := utils.ResultAesDecrypt(c, string(body)) | |||
if str != "" { | |||
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer([]byte(str))) | |||
} | |||
} | |||
} | |||
c.Next() | |||
} |
@@ -1,22 +0,0 @@ | |||
package mw | |||
import ( | |||
"strings" | |||
"github.com/gin-gonic/gin" | |||
"applet/app/e" | |||
"applet/app/md" | |||
) | |||
// 检查设备等, 把头部信息下放到hdl可以获取 | |||
func Checker(c *gin.Context) { | |||
// 校验平台支持 | |||
platform := strings.ToLower(c.GetHeader("Platform")) | |||
//fmt.Println(platform) | |||
if _, ok := md.PlatformList[platform]; !ok { | |||
e.OutErr(c, e.ERR_PLATFORM) | |||
return | |||
} | |||
c.Next() | |||
} |
@@ -1,93 +0,0 @@ | |||
package mw | |||
import ( | |||
"applet/app/svc" | |||
"errors" | |||
"fmt" | |||
"github.com/gin-gonic/gin" | |||
"strings" | |||
"applet/app/db" | |||
"applet/app/e" | |||
"applet/app/md" | |||
) | |||
// DB is 中间件 用来检查master_id是否有对应的数据库engine | |||
func DB(c *gin.Context) { | |||
fmt.Println(c.Request.Header) | |||
masterID := c.GetHeader("master_id") | |||
fmt.Println("master_id", masterID) | |||
if masterID == "" { | |||
fmt.Println("not found master_id found MasterId start") | |||
masterID = c.GetHeader("MasterId") | |||
fmt.Println("MasterId", masterID) | |||
// if masterID still emtpy | |||
if masterID == "" { | |||
platform := c.GetHeader("Platform") | |||
if platform == md.PLATFORM_WAP { | |||
// H5 要根据域名去获取mid | |||
hostList := strings.Split(c.Request.Host, ".") | |||
if len(hostList) == 4 && (hostList[2]+"."+hostList[3] == "zhiyingos.com" || hostList[2]+"."+hostList[3] == "izhyin.com") { | |||
// 官方域名 | |||
masterID = hostList[1] | |||
} else { | |||
// 自定义域名 | |||
masterID = svc.GetWebSiteDomainMasterId(md.PLATFORM_WAP, c.Request.Host) | |||
} | |||
//requestURL := cfg.Official.URL + "/api/user/check" | |||
//fmt.Println(c.Request.Host) | |||
//client := &http.Client{ | |||
// Timeout: time.Duration(time.Second * 2), | |||
//} | |||
//data := []byte(fmt.Sprintf(`{"domain":"%s"}`, c.Request.Host)) | |||
//body := bytes.NewReader(data) | |||
//request, err := http.NewRequest("POST", requestURL, body) | |||
//if err != nil { | |||
// e.OutErr(c, e.ERR_MASTER_ID, errors.New("not found master_id in DBs")) | |||
// return | |||
//} | |||
//request.Header.Set("Content-Type", "application/json;charset=UTF-8") | |||
//resp, err := client.Do(request.WithContext(context.TODO())) | |||
//if err != nil { | |||
// e.OutErr(c, e.ERR_MASTER_ID, err) | |||
// return | |||
//} | |||
//defer resp.Body.Close() | |||
//respBytes, err := ioutil.ReadAll(resp.Body) | |||
//if err != nil { | |||
// e.OutErr(c, e.ERR_MASTER_ID, err) | |||
// return | |||
//} | |||
//mid := gjson.GetBytes(respBytes, "data.db_master_id").String() | |||
//if mid == "" { | |||
// e.OutErr(c, e.ERR_MASTER_ID, errors.New("not found master_id in DBs")) | |||
// return | |||
//} | |||
//masterID = mid | |||
} | |||
} | |||
} | |||
_, ok := db.DBs[masterID] | |||
if !ok { | |||
e.OutErr(c, e.ERR_MASTER_ID, errors.New("not found master_id in DBs")) | |||
return | |||
} | |||
fmt.Println("master_id", masterID) | |||
c.Set("mid", masterID) | |||
//判断是否有独立域名 | |||
domain_wap_base := svc.GetWebSiteDomainInfo(c, "wap") | |||
httpStr := "http://" | |||
if c.GetHeader("Platform") == md.PLATFORM_WX_APPLET || c.GetHeader("Platform") == md.PLATFORM_ALIPAY_APPLET || c.GetHeader("Platform") == md.PLATFORM_BAIDU_APPLET || c.GetHeader("Platform") == md.PLATFORM_TOUTIAO_APPLET || c.GetHeader("Platform") == md.PLATFORM_TIKTOK_APPLET { | |||
httpStr = "https://" | |||
domain_wap_base = strings.Replace(domain_wap_base, "http://", httpStr, 1) | |||
} | |||
c.Set("domain_wap_base", domain_wap_base) | |||
c.Set("http_host", httpStr) | |||
c.Set("h5_api_secret_key", svc.SysCfgGet(c, "h5_api_secret_key")) | |||
c.Set("app_api_secret_key", svc.SysCfgGet(c, "app_api_secret_key")) | |||
c.Set("applet_api_secret_key", svc.SysCfgGet(c, "applet_api_secret_key")) | |||
c.Next() | |||
} |
@@ -6,6 +6,8 @@ import ( | |||
"applet/app/mw" | |||
_ "applet/docs" | |||
"github.com/gin-gonic/gin" | |||
swaggerFiles "github.com/swaggo/files" | |||
ginSwagger "github.com/swaggo/gin-swagger" | |||
) | |||
// 初始化路由 | |||
@@ -18,15 +20,16 @@ func Init() *gin.Engine { | |||
gin.SetMode(mode) | |||
//创建一个新的启动器 | |||
r := gin.New() | |||
r.Use(mw.ChangeHeader) | |||
r.GET("/api/swagger/*any", func(c *gin.Context) { | |||
// r.Use(mw.SwagAuth()) | |||
ginSwagger.DisablingWrapHandler(swaggerFiles.Handler, "SWAGGER")(c) | |||
}) | |||
// 是否打印访问日志, 在非正式环境都打印 | |||
if mode != "release" { | |||
r.Use(gin.Logger()) | |||
} | |||
r.Use(gin.Recovery()) | |||
// r.Use(mw.Limiter) | |||
//r.LoadHTMLGlob("static/html/*") | |||
r.GET("/favicon.ico", func(c *gin.Context) { | |||
c.Status(204) | |||
@@ -38,36 +41,13 @@ func Init() *gin.Engine { | |||
c.JSON(405, gin.H{"code": 405, "msg": "method not allowed", "data": []struct{}{}}) | |||
}) | |||
r.Use(mw.Cors) | |||
route(r.Group("/api/v1/mall")) | |||
rInApi(r.Group("/inapi/mall")) | |||
route(r.Group("/api")) | |||
return r | |||
} | |||
func route(r *gin.RouterGroup) { | |||
r.GET("/test", hdl.Demo) | |||
r.Use(mw.DB) // 以下接口需要用到数据库 | |||
{ | |||
} | |||
r.Use(mw.CheckBody) //body参数转换 | |||
r.Use(mw.CheckSign) //签名校验 | |||
r.Use(mw.Checker) // 以下接口需要检查Header: platform | |||
{ | |||
} | |||
r.Use(mw.AuthJWT) // 以下接口需要JWT验证 | |||
{ | |||
} | |||
} | |||
func rInApi(r *gin.RouterGroup) { | |||
//TODO::该分组中所有的接口,支持开放平台调用 | |||
r.Use(mw.DB) // 以下接口需要用到数据库 | |||
{ | |||
} | |||
r.Use(mw.AuthJWT) // 以下接口需要JWT验证 | |||
r.Use(mw.Auth) // 以下接口需要JWT验证 | |||
{ | |||
} | |||
@@ -0,0 +1,55 @@ | |||
package svc | |||
import ( | |||
"applet/app/db" | |||
"applet/app/lib/auth" | |||
"code.fnuoos.com/EggPlanet/egg_models.git/src/implement" | |||
"code.fnuoos.com/EggPlanet/egg_models.git/src/model" | |||
"errors" | |||
"github.com/gin-gonic/gin" | |||
"strings" | |||
"time" | |||
) | |||
func GetUser(c *gin.Context) *model.Admin { | |||
admin, _ := c.Get("admin") | |||
if admin == nil { | |||
return &model.Admin{ | |||
AdmId: 0, | |||
Username: "", | |||
Password: "", | |||
State: 0, | |||
IsSuperAdministrator: 0, | |||
IsObserverAdministrator: 0, | |||
Memo: "", | |||
CreateAt: time.Now().Format("2006-01-02 15:04:05"), | |||
UpdateAt: time.Now().Format("2006-01-02 15:04:05"), | |||
} | |||
} | |||
return admin.(*model.Admin) | |||
} | |||
func CheckUser(c *gin.Context) (*model.Admin, error) { | |||
token := c.GetHeader("Authorization") | |||
if token == "" { | |||
return nil, errors.New("token not exist") | |||
} | |||
// 按空格分割 | |||
parts := strings.SplitN(token, " ", 2) | |||
if !(len(parts) == 2 && parts[0] == "Bearer") { | |||
return nil, errors.New("token format error") | |||
} | |||
// parts[1]是获取到的tokenString,我们使用之前定义好的解析JWT的函数来解析它 | |||
mc, err := auth.ParseToken(parts[1]) | |||
if err != nil { | |||
return nil, err | |||
} | |||
// 获取admin | |||
adminDb := implement.NewAdminDb(db.Db) | |||
user, err := adminDb.GetAdmin(mc.AdmId) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return user, nil | |||
} |
@@ -1,11 +0,0 @@ | |||
package svc | |||
import ( | |||
"applet/app/db" | |||
"github.com/gin-gonic/gin" | |||
"xorm.io/xorm" | |||
) | |||
func MasterDb(c *gin.Context) *xorm.Engine { | |||
return db.DBs[c.GetString("mid")] | |||
} |
@@ -1,85 +0,0 @@ | |||
package svc | |||
import ( | |||
"applet/app/md" | |||
"applet/app/utils" | |||
"applet/app/utils/cache" | |||
"errors" | |||
"fmt" | |||
"math/rand" | |||
"reflect" | |||
"time" | |||
) | |||
const redisMutexLockExpTime = 15 | |||
// TryGetDistributedLock 分布式锁获取 | |||
// requestId 用于标识请求客户端,可以是随机字符串,需确保唯一 | |||
func TryGetDistributedLock(lockKey, requestId string, isNegative bool) bool { | |||
if isNegative { // 多次尝试获取 | |||
retry := 1 | |||
for { | |||
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") | |||
// 获取锁成功 | |||
if err == nil && ok == "OK" { | |||
return true | |||
} | |||
// 尝试多次没获取成功 | |||
if retry > 10 { | |||
return false | |||
} | |||
time.Sleep(time.Millisecond * time.Duration(rand.Intn(1000))) | |||
retry += 1 | |||
} | |||
} else { // 只尝试一次 | |||
ok, err := cache.Do("SET", lockKey, requestId, "EX", redisMutexLockExpTime, "NX") | |||
// 获取锁成功 | |||
if err == nil && ok == "OK" { | |||
return true | |||
} | |||
return false | |||
} | |||
} | |||
// ReleaseDistributedLock 释放锁,通过比较requestId,用于确保客户端只释放自己的锁,使用lua脚本保证操作的原子型 | |||
func ReleaseDistributedLock(lockKey, requestId string) (bool, error) { | |||
luaScript := ` | |||
if redis.call("get",KEYS[1]) == ARGV[1] | |||
then | |||
return redis.call("del",KEYS[1]) | |||
else | |||
return 0 | |||
end` | |||
do, err := cache.Do("eval", luaScript, 1, lockKey, requestId) | |||
fmt.Println(reflect.TypeOf(do)) | |||
fmt.Println(do) | |||
if utils.AnyToInt64(do) == 1 { | |||
return true, err | |||
} else { | |||
return false, err | |||
} | |||
} | |||
func GetDistributedLockRequestId(prefix string) string { | |||
return prefix + utils.IntToStr(rand.Intn(100000000)) | |||
} | |||
// HandleBalanceDistributedLock 处理余额更新时获取锁和释放锁 如果加锁成功,使用语句 ` defer cb() ` 释放锁 | |||
func HandleBalanceDistributedLock(masterId, uid, requestIdPrefix string) (cb func(), err error) { | |||
// 获取余额更新锁 | |||
balanceLockKey := fmt.Sprintf(md.UserFinValidUpdateLock, masterId, uid) | |||
requestId := GetDistributedLockRequestId(requestIdPrefix) | |||
balanceLockOk := TryGetDistributedLock(balanceLockKey, requestId, true) | |||
if !balanceLockOk { | |||
return nil, errors.New("系统繁忙,请稍后再试") | |||
} | |||
cb = func() { | |||
_, _ = ReleaseDistributedLock(balanceLockKey, requestId) | |||
} | |||
return cb, nil | |||
} |
@@ -1,175 +0,0 @@ | |||
package svc | |||
import ( | |||
"errors" | |||
"github.com/gin-gonic/gin" | |||
"strings" | |||
"xorm.io/xorm" | |||
"applet/app/cfg" | |||
"applet/app/db" | |||
"applet/app/md" | |||
"applet/app/utils" | |||
"applet/app/utils/cache" | |||
) | |||
// 单挑记录获取 | |||
func SysCfgGet(c *gin.Context, key string) string { | |||
mid := c.GetString("mid") | |||
eg := db.DBs[mid] | |||
return db.SysCfgGetWithDb(eg, mid, key) | |||
} | |||
// 多条记录获取 | |||
func SysCfgFind(c *gin.Context, keys ...string) map[string]string { | |||
var masterId string | |||
if c == nil { | |||
masterId = "" | |||
} else { | |||
masterId = c.GetString("mid") | |||
} | |||
tmp := SysCfgFindComm(masterId, keys...) | |||
return tmp | |||
} | |||
func SysCfgFindComm(masterId string, keys ...string) map[string]string { | |||
var eg *xorm.Engine | |||
if masterId == "" { | |||
eg = db.Db | |||
} else { | |||
eg = db.DBs[masterId] | |||
} | |||
res := map[string]string{} | |||
//TODO::判断keys长度(大于10个直接查数据库) | |||
if len(keys) > 10 { | |||
cfgList, _ := db.SysCfgGetAll(eg) | |||
if cfgList == nil { | |||
return nil | |||
} | |||
for _, v := range *cfgList { | |||
res[v.Key] = v.Val | |||
} | |||
} else { | |||
for _, key := range keys { | |||
res[key] = db.SysCfgGetWithDb(eg, masterId, key) | |||
} | |||
} | |||
return res | |||
} | |||
// 多条记录获取 | |||
func EgSysCfgFind(keys ...string) map[string]string { | |||
var e *xorm.Engine | |||
res := map[string]string{} | |||
if len(res) == 0 { | |||
cfgList, _ := db.SysCfgGetAll(e) | |||
if cfgList == nil { | |||
return nil | |||
} | |||
for _, v := range *cfgList { | |||
res[v.Key] = v.Val | |||
} | |||
// 先不设置缓存 | |||
// cache.SetJson(md.KEY_SYS_CFG_CACHE, res, 60) | |||
} | |||
if len(keys) == 0 { | |||
return res | |||
} | |||
tmp := map[string]string{} | |||
for _, v := range keys { | |||
if val, ok := res[v]; ok { | |||
tmp[v] = val | |||
} else { | |||
tmp[v] = "" | |||
} | |||
} | |||
return tmp | |||
} | |||
// 清理系统配置信息 | |||
func SysCfgCleanCache() { | |||
cache.Del(md.KEY_SYS_CFG_CACHE) | |||
} | |||
// 写入系统设置 | |||
func SysCfgSet(c *gin.Context, key, val, memo string) bool { | |||
cfg, err := db.SysCfgGetOne(db.DBs[c.GetString("mid")], key) | |||
if err != nil || cfg == nil { | |||
return db.SysCfgInsert(db.DBs[c.GetString("mid")], key, val, memo) | |||
} | |||
if memo != "" && cfg.Memo != memo { | |||
cfg.Memo = memo | |||
} | |||
SysCfgCleanCache() | |||
return db.SysCfgUpdate(db.DBs[c.GetString("mid")], key, val, cfg.Memo) | |||
} | |||
// 多条记录获取 | |||
func SysCfgFindByIds(eg *xorm.Engine, keys ...string) map[string]string { | |||
key := utils.Md5(eg.DataSourceName() + md.KEY_SYS_CFG_CACHE) | |||
res := map[string]string{} | |||
c, ok := cfg.MemCache.Get(key).(map[string]string) | |||
if !ok || len(c) == 0 { | |||
cfgList, _ := db.DbsSysCfgGetAll(eg) | |||
if cfgList == nil { | |||
return nil | |||
} | |||
for _, v := range *cfgList { | |||
res[v.Key] = v.Val | |||
} | |||
cfg.MemCache.Put(key, res, 10) | |||
} else { | |||
res = c | |||
} | |||
if len(keys) == 0 { | |||
return res | |||
} | |||
tmp := map[string]string{} | |||
for _, v := range keys { | |||
if val, ok := res[v]; ok { | |||
tmp[v] = val | |||
} else { | |||
tmp[v] = "" | |||
} | |||
} | |||
return tmp | |||
} | |||
// 支付配置 | |||
func SysCfgFindPayment(c *gin.Context) ([]map[string]string, error) { | |||
platform := c.GetHeader("platform") | |||
payCfg := SysCfgFind(c, "pay_wx_pay_img", "pay_ali_pay_img", "pay_balance_img", "pay_type") | |||
if payCfg["pay_wx_pay_img"] == "" || payCfg["pay_ali_pay_img"] == "" || payCfg["pay_balance_img"] == "" || payCfg["pay_type"] == "" { | |||
return nil, errors.New("lack of payment config") | |||
} | |||
payCfg["pay_wx_pay_img"] = ImageFormat(c, payCfg["pay_wx_pay_img"]) | |||
payCfg["pay_ali_pay_img"] = ImageFormat(c, payCfg["pay_ali_pay_img"]) | |||
payCfg["pay_balance_img"] = ImageFormat(c, payCfg["pay_balance_img"]) | |||
var result []map[string]string | |||
if strings.Contains(payCfg["pay_type"], "aliPay") && platform != md.PLATFORM_WX_APPLET { | |||
item := make(map[string]string) | |||
item["pay_channel"] = "alipay" | |||
item["img"] = payCfg["pay_ali_pay_img"] | |||
item["name"] = "支付宝支付" | |||
result = append(result, item) | |||
} | |||
if strings.Contains(payCfg["pay_type"], "wxPay") { | |||
item := make(map[string]string) | |||
item["pay_channel"] = "wx" | |||
item["img"] = payCfg["pay_wx_pay_img"] | |||
item["name"] = "微信支付" | |||
result = append(result, item) | |||
} | |||
if strings.Contains(payCfg["pay_type"], "walletPay") { | |||
item := make(map[string]string) | |||
item["pay_channel"] = "fin" | |||
item["img"] = payCfg["pay_balance_img"] | |||
item["name"] = "余额支付" | |||
result = append(result, item) | |||
} | |||
return result, nil | |||
} |
@@ -5,17 +5,21 @@ import ( | |||
"applet/app/utils" | |||
"applet/app/utils/logx" | |||
"encoding/json" | |||
"errors" | |||
"fmt" | |||
"github.com/go-playground/validator/v10" | |||
) | |||
// HandleValidateErr 通用请求参数错误处理 | |||
func HandleValidateErr(err error) error { | |||
switch err.(type) { | |||
case *json.UnmarshalTypeError: | |||
var unmarshalTypeError *json.UnmarshalTypeError | |||
var validationErrors validator.ValidationErrors | |||
switch { | |||
case errors.As(err, &unmarshalTypeError): | |||
return e.NewErr(e.ERR_UNMARSHAL, "参数格式错误") | |||
case validator.ValidationErrors: | |||
errs := err.(validator.ValidationErrors) | |||
case errors.As(err, &validationErrors): | |||
var errs validator.ValidationErrors | |||
errors.As(err, &errs) | |||
transMsgMap := errs.Translate(utils.ValidatorTrans) | |||
transMsgOne := transMsgMap[utils.GetOneKeyOfMapString(transMsgMap)] | |||
return e.NewErr(e.ERR_INVALID_ARGS, transMsgOne) | |||
@@ -1,12 +1,9 @@ | |||
package utils | |||
import ( | |||
"applet/app/cfg" | |||
"bytes" | |||
"crypto/aes" | |||
"crypto/cipher" | |||
"encoding/base64" | |||
"encoding/json" | |||
"fmt" | |||
) | |||
@@ -124,49 +121,3 @@ func pKCS5Trimming(encrypt []byte) []byte { | |||
padding := encrypt[len(encrypt)-1] | |||
return encrypt[:len(encrypt)-int(padding)] | |||
} | |||
// AesAdminCurlPOST is 与后台接口加密交互 | |||
func AesAdminCurlPOST(aesData string, url string) ([]byte, error) { | |||
adminKey := cfg.Admin.AesKey | |||
adminVI := cfg.Admin.AesIV | |||
crypto := AesCrypt{ | |||
Key: []byte(adminKey), | |||
Iv: []byte(adminVI), | |||
} | |||
encrypt, err := crypto.Encrypt([]byte(aesData)) | |||
if err != nil { | |||
return nil, err | |||
} | |||
// 发送请求到后台 | |||
postData := map[string]string{ | |||
"postData": base64.StdEncoding.EncodeToString(encrypt), | |||
} | |||
fmt.Println(adminKey) | |||
fmt.Println(adminVI) | |||
fmt.Println("=======ADMIN请求=====") | |||
fmt.Println(postData) | |||
postDataByte, _ := json.Marshal(postData) | |||
rdata, err := CurlPost(url, postDataByte, nil) | |||
fmt.Println(err) | |||
if err != nil { | |||
return nil, err | |||
} | |||
fmt.Println(rdata) | |||
pass, err := base64.StdEncoding.DecodeString(string(rdata)) | |||
if err != nil { | |||
return nil, err | |||
} | |||
fmt.Println(pass) | |||
decrypt, err := crypto.Decrypt(pass) | |||
fmt.Println(err) | |||
if err != nil { | |||
return nil, err | |||
} | |||
return decrypt, nil | |||
} |
@@ -1,46 +0,0 @@ | |||
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") | |||
} |
@@ -1,55 +1,104 @@ | |||
module applet | |||
go 1.18 | |||
go 1.22.0 | |||
replace code.fnuoos.com/EggPlanet/egg_models.git => E:/company/Egg/egg_models | |||
require ( | |||
code.fnuoos.com/EggPlanet/egg_models.git v0.0.0-20241030143505-e9a8ea068840 | |||
code.fnuoos.com/go_rely_warehouse/zyos_go_mq.git v0.0.5 | |||
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5 | |||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 | |||
github.com/antchfx/htmlquery v1.3.2 // indirect | |||
github.com/antchfx/xmlquery v1.4.1 // indirect | |||
github.com/boombuler/barcode v1.0.1 | |||
github.com/dchest/uniuri v0.0.0-20200228104902-7aecb25e1fe5 | |||
github.com/dgrijalva/jwt-go v3.2.0+incompatible | |||
github.com/forgoer/openssl v0.0.0-20201023062029-c3112b0c8700 | |||
github.com/gin-contrib/sessions v0.0.3 | |||
github.com/gin-gonic/gin v1.6.3 | |||
github.com/go-openapi/spec v0.20.3 // indirect | |||
github.com/go-openapi/swag v0.19.15 // indirect | |||
github.com/go-playground/locales v0.13.0 | |||
github.com/go-playground/universal-translator v0.17.0 | |||
github.com/go-playground/validator/v10 v10.4.2 | |||
github.com/gin-gonic/gin v1.9.0 | |||
github.com/go-playground/locales v0.14.1 | |||
github.com/go-playground/universal-translator v0.18.1 | |||
github.com/go-playground/validator/v10 v10.11.2 | |||
github.com/go-redis/redis v6.15.9+incompatible | |||
github.com/go-sql-driver/mysql v1.6.0 | |||
github.com/gobwas/glob v0.2.3 // indirect | |||
github.com/go-sql-driver/mysql v1.8.1 | |||
github.com/gocolly/colly v1.2.0 | |||
github.com/golang/protobuf v1.5.2 // indirect | |||
github.com/golang/snappy v0.0.3 // indirect | |||
github.com/gomodule/redigo v2.0.0+incompatible | |||
github.com/iGoogle-ink/gopay v1.5.36 | |||
github.com/makiuchi-d/gozxing v0.0.0-20210324052758-57132e828831 | |||
github.com/qiniu/api.v7/v7 v7.8.2 | |||
github.com/robfig/cron/v3 v3.0.1 | |||
github.com/sony/sonyflake v1.0.0 | |||
github.com/swaggo/swag v1.8.12 | |||
github.com/syyongx/php2go v0.9.8 | |||
github.com/tidwall/gjson v1.7.4 | |||
go.uber.org/zap v1.16.0 | |||
gopkg.in/natefinch/lumberjack.v2 v2.2.1 | |||
gopkg.in/yaml.v2 v2.4.0 | |||
xorm.io/xorm v1.3.1 | |||
) | |||
require ( | |||
filippo.io/edwards25519 v1.1.0 // indirect | |||
github.com/KyleBanks/depth v1.2.1 // indirect | |||
github.com/PuerkitoBio/goquery v1.5.1 // indirect | |||
github.com/PuerkitoBio/purell v1.1.1 // indirect | |||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect | |||
github.com/andybalholm/cascadia v1.1.0 // indirect | |||
github.com/antchfx/htmlquery v1.3.2 // indirect | |||
github.com/antchfx/xmlquery v1.4.1 // indirect | |||
github.com/antchfx/xpath v1.3.1 // indirect | |||
github.com/bytedance/sonic v1.8.0 // indirect | |||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect | |||
github.com/gin-contrib/sse v0.1.0 // indirect | |||
github.com/go-openapi/jsonpointer v0.19.5 // indirect | |||
github.com/go-openapi/jsonreference v0.19.6 // indirect | |||
github.com/go-openapi/spec v0.20.4 // 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/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | |||
github.com/golang/protobuf v1.5.2 // indirect | |||
github.com/golang/snappy v0.0.4 // indirect | |||
github.com/gookit/color v1.3.8 // indirect | |||
github.com/gorilla/context v1.1.1 // indirect | |||
github.com/gorilla/securecookie v1.1.1 // indirect | |||
github.com/gorilla/sessions v1.2.1 // indirect | |||
github.com/iGoogle-ink/gopay v1.5.36 | |||
github.com/iGoogle-ink/gotil v1.0.20 | |||
github.com/json-iterator/go v1.1.10 // indirect | |||
github.com/josharian/intern v1.0.0 // indirect | |||
github.com/json-iterator/go v1.1.12 // indirect | |||
github.com/kennygrant/sanitize v1.2.4 // indirect | |||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect | |||
github.com/leodido/go-urn v1.2.1 // indirect | |||
github.com/mailru/easyjson v0.7.7 // indirect | |||
github.com/makiuchi-d/gozxing v0.0.0-20210324052758-57132e828831 | |||
github.com/pkg/errors v0.9.1 | |||
github.com/qiniu/api.v7/v7 v7.8.2 | |||
github.com/robfig/cron/v3 v3.0.1 | |||
github.com/mattn/go-isatty v0.0.19 // indirect | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | |||
github.com/modern-go/reflect2 v1.0.2 // indirect | |||
github.com/onsi/ginkgo v1.15.0 // indirect | |||
github.com/onsi/gomega v1.10.5 // indirect | |||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect | |||
github.com/pkg/errors v0.9.1 // indirect | |||
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect | |||
github.com/sony/sonyflake v1.0.0 | |||
github.com/swaggo/swag v1.7.0 | |||
github.com/syyongx/php2go v0.9.4 | |||
github.com/streadway/amqp v1.0.0 // indirect | |||
github.com/swaggo/files v1.0.1 // indirect | |||
github.com/swaggo/gin-swagger v1.6.0 // indirect | |||
github.com/syndtr/goleveldb v1.0.0 // indirect | |||
github.com/temoto/robotstxt v1.1.2 // indirect | |||
github.com/tidwall/gjson v1.7.4 | |||
github.com/ugorji/go v1.2.5 // indirect | |||
github.com/tidwall/match v1.0.3 // indirect | |||
github.com/tidwall/pretty v1.1.0 // indirect | |||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | |||
github.com/ugorji/go/codec v1.2.9 // indirect | |||
go.uber.org/atomic v1.7.0 // indirect | |||
go.uber.org/multierr v1.6.0 // indirect | |||
go.uber.org/zap v1.16.0 | |||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect | |||
golang.org/x/crypto v0.28.0 // indirect | |||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b // indirect | |||
gopkg.in/natefinch/lumberjack.v2 v2.0.0 | |||
gopkg.in/yaml.v2 v2.4.0 | |||
honnef.co/go/tools v0.0.1-2020.1.4 // indirect | |||
xorm.io/builder v0.3.9 // indirect | |||
xorm.io/xorm v1.0.7 | |||
golang.org/x/net v0.30.0 // indirect | |||
golang.org/x/sync v0.8.0 // indirect | |||
golang.org/x/sys v0.26.0 // indirect | |||
golang.org/x/text v0.19.0 // indirect | |||
golang.org/x/tools v0.26.0 // indirect | |||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect | |||
google.golang.org/appengine v1.6.1 // indirect | |||
google.golang.org/protobuf v1.28.1 // indirect | |||
gopkg.in/yaml.v3 v3.0.1 // indirect | |||
honnef.co/go/tools v0.1.3 // indirect | |||
xorm.io/builder v0.3.11-0.20220531020008-1bd24a7dc978 // indirect | |||
) |
@@ -0,0 +1,90 @@ | |||
kind: Deployment | |||
apiVersion: apps/v1 | |||
# 元数据 | |||
metadata: | |||
name: advertisement | |||
namespace: advertisement | |||
labels: | |||
app: advertisement | |||
annotations: | |||
kubesphere.io/creator: dengbiao | |||
kubesphere.io/description: advertisement | |||
# deployment主要部分 | |||
spec: | |||
replicas: 1 | |||
selector: | |||
matchLabels: | |||
# 名称与上面的labels对应 | |||
app: advertisement | |||
template: | |||
metadata: | |||
labels: | |||
# 名称与上面的matchLabels对应 | |||
app: advertisement | |||
spec: | |||
# 声明挂载卷(将外部已存在的pvc、config等挂载进来) | |||
volumes: | |||
# 用于时区校正 | |||
- name: host-time | |||
hostPath: | |||
path: /etc/localtime | |||
type: '' | |||
# 将前面创建的configMap也挂载进来 | |||
- name: advertisement-cfg | |||
configMap: | |||
# 这里的名字就是前面创建的configMap的名字 | |||
name: advertisement-cfg | |||
defaultMode: 420 | |||
# pvc | |||
- name: advertisement # 在该部署中的名称,后面使用改名称挂载 | |||
persistentVolumeClaim: | |||
claimName: advertisement # pvc的名称 | |||
# Nginx配置 | |||
- name: advertisement-nginx | |||
configMap: | |||
name: advertisement-nginx # 外部configMap的名称 | |||
items: | |||
- key: go.conf | |||
path: default.conf | |||
containers: | |||
# 主容器 | |||
- name: advertisement-container | |||
# 镜像地址(提前打包好并推送的镜像仓库) | |||
image: 'registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/advertisement:0.0.1' | |||
ports: | |||
- name: ad-1002 | |||
# 容器端口号(注意与golang web server启动的端口一致) | |||
containerPort: 1002 | |||
protocol: TCP | |||
# 将前面volume声明的需要用到的pvc、config挂载上来 | |||
volumeMounts: | |||
- name: host-time | |||
readOnly: true | |||
mountPath: /etc/localtime | |||
- name: advertisement-cfg # 该名字对应前面volumes声明的名字 | |||
readOnly: true | |||
# 挂载到容器的哪个路径 | |||
mountPath: /var/zyos | |||
imagePullPolicy: Always | |||
# Nginx 容器 | |||
- name: nginx | |||
image: 'registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/nginx:latest' | |||
ports: | |||
- name: http-80 | |||
containerPort: 80 | |||
protocol: TCP | |||
volumeMounts: | |||
# 时区校正 | |||
- name: host-time | |||
readOnly: true | |||
mountPath: /etc/localtime | |||
# 存储卷 用于存放前端代码 | |||
- name: advertisement # 前面volumes声明的名称 | |||
mountPath: /usr/share/nginx/html | |||
- name: advertisement-nginx # Nginx 配置 | |||
readOnly: true | |||
mountPath: /etc/nginx/conf.d/default.conf | |||
subPath: default.conf | |||
restartPolicy: Always | |||
terminationGracePeriodSeconds: 30 | |||
dnsPolicy: ClusterFirst |
@@ -0,0 +1,90 @@ | |||
kind: Deployment | |||
apiVersion: apps/v1 | |||
# 元数据 | |||
metadata: | |||
name: advertisement | |||
namespace: advertisement | |||
labels: | |||
app: advertisement | |||
annotations: | |||
kubesphere.io/creator: dengbiao | |||
kubesphere.io/description: advertisement | |||
# deployment主要部分 | |||
spec: | |||
replicas: 1 | |||
selector: | |||
matchLabels: | |||
# 名称与上面的labels对应 | |||
app: advertisement | |||
template: | |||
metadata: | |||
labels: | |||
# 名称与上面的matchLabels对应 | |||
app: advertisement | |||
spec: | |||
# 声明挂载卷(将外部已存在的pvc、config等挂载进来) | |||
volumes: | |||
# 用于时区校正 | |||
- name: host-time | |||
hostPath: | |||
path: /etc/localtime | |||
type: '' | |||
# 将前面创建的configMap也挂载进来 | |||
- name: advertisement-cfg | |||
configMap: | |||
# 这里的名字就是前面创建的configMap的名字 | |||
name: advertisement-cfg | |||
defaultMode: 420 | |||
# pvc | |||
- name: advertisement-pvc # 在该部署中的名称,后面使用改名称挂载 | |||
persistentVolumeClaim: | |||
claimName: advertisement-pvc # pvc的名称 | |||
# Nginx配置 | |||
- name: advertisement-nginx | |||
configMap: | |||
name: advertisement-nginx # 外部configMap的名称 | |||
items: | |||
- key: go.conf | |||
path: default.conf | |||
containers: | |||
# 主容器 | |||
- name: advertisement-container | |||
# 镜像地址(提前打包好并推送的镜像仓库) | |||
image: 'registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/advertisement:0.0.1' | |||
ports: | |||
- name: ad-1002 | |||
# 容器端口号(注意与golang web server启动的端口一致) | |||
containerPort: 1002 | |||
protocol: TCP | |||
# 将前面volume声明的需要用到的pvc、config挂载上来 | |||
volumeMounts: | |||
- name: host-time | |||
readOnly: true | |||
mountPath: /etc/localtime | |||
- name: advertisement-cfg # 该名字对应前面volumes声明的名字 | |||
readOnly: true | |||
# 挂载到容器的哪个路径 | |||
mountPath: /var/zyos | |||
imagePullPolicy: Always | |||
# Nginx 容器 | |||
- name: nginx | |||
image: 'registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/nginx:latest' | |||
ports: | |||
- name: http-80 | |||
containerPort: 80 | |||
protocol: TCP | |||
volumeMounts: | |||
# 时区校正 | |||
- name: host-time | |||
readOnly: true | |||
mountPath: /etc/localtime | |||
# 存储卷 用于存放前端代码 | |||
- name: advertisement-pvc # 前面volumes声明的名称 | |||
mountPath: /usr/share/nginx/html | |||
- name: advertisement-nginx # Nginx 配置 | |||
readOnly: true | |||
mountPath: /etc/nginx/conf.d/default.conf | |||
subPath: default.conf | |||
restartPolicy: Always | |||
terminationGracePeriodSeconds: 30 | |||
dnsPolicy: ClusterFirst |
@@ -1,56 +0,0 @@ | |||
kind: Deployment | |||
apiVersion: apps/v1 | |||
metadata: | |||
name: mall-task | |||
namespace: zhios | |||
labels: | |||
app: mall-task | |||
annotations: | |||
kubesphere.io/creator: wuhanqin | |||
kubesphere.io/description: 自营商城go定时任务 | |||
spec: | |||
replicas: 1 | |||
selector: | |||
matchLabels: | |||
app: mall-task | |||
template: | |||
metadata: | |||
labels: | |||
app: mall-task | |||
spec: | |||
volumes: | |||
- name: host-time | |||
hostPath: | |||
path: /etc/localtime | |||
type: '' | |||
- name: mall-task-cfg1 | |||
configMap: | |||
name: zhios-mall-task | |||
items: | |||
- key: task.yml | |||
path: task.yml | |||
defaultMode: 420 | |||
containers: | |||
- name: container-mall-task | |||
image: 'registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/zyos-mall-task:0.3' | |||
resources: | |||
limits: | |||
cpu: '1' | |||
memory: 1000Mi | |||
requests: | |||
cpu: 200m | |||
memory: 1000Mi | |||
volumeMounts: | |||
- name: host-time | |||
readOnly: true | |||
mountPath: /etc/localtime | |||
- name: mall-task-cfg1 | |||
readOnly: true | |||
mountPath: /var/zyos/task.yml | |||
subPath: task.yml | |||
terminationMessagePath: /dev/termination-log | |||
terminationMessagePolicy: File | |||
imagePullPolicy: Always | |||
restartPolicy: Always | |||
terminationGracePeriodSeconds: 30 | |||
dnsPolicy: ClusterFirst |
@@ -1,56 +0,0 @@ | |||
kind: Deployment | |||
apiVersion: apps/v1 | |||
metadata: | |||
name: mall-task | |||
namespace: dev | |||
labels: | |||
app: mall-task | |||
annotations: | |||
kubesphere.io/creator: wuhanqin | |||
kubesphere.io/description: 自营商城go定时任务 | |||
spec: | |||
replicas: 1 | |||
selector: | |||
matchLabels: | |||
app: mall-task | |||
template: | |||
metadata: | |||
labels: | |||
app: mall-task | |||
spec: | |||
volumes: | |||
- name: host-time | |||
hostPath: | |||
path: /etc/localtime | |||
type: '' | |||
- name: mall-task-cfg1 | |||
configMap: | |||
name: mall-task-cfg | |||
items: | |||
- key: task.yml | |||
path: task.yml | |||
defaultMode: 420 | |||
containers: | |||
- name: container-mall-task | |||
image: 'registry.cn-shenzhen.aliyuncs.com/fnuoos-prd/zyos-mall-task:0.1' | |||
resources: | |||
limits: | |||
cpu: '1' | |||
memory: 1000Mi | |||
requests: | |||
cpu: 200m | |||
memory: 1000Mi | |||
volumeMounts: | |||
- name: host-time | |||
readOnly: true | |||
mountPath: /etc/localtime | |||
- name: mall-task-cfg1 | |||
readOnly: true | |||
mountPath: /var/zyos/task.yml | |||
subPath: task.yml | |||
terminationMessagePath: /dev/termination-log | |||
terminationMessagePolicy: File | |||
imagePullPolicy: Always | |||
restartPolicy: Always | |||
terminationGracePeriodSeconds: 30 | |||
dnsPolicy: ClusterFirst |
@@ -1,49 +0,0 @@ | |||
apiVersion: apps/v1 | |||
kind: Deployment | |||
metadata: | |||
namespace: zhios | |||
name: zhios-mall | |||
labels: | |||
app: zhios-mall | |||
spec: | |||
replicas: 1 | |||
template: | |||
metadata: | |||
name: zhios-mall | |||
labels: | |||
app: zhios-mall | |||
spec: | |||
containers: | |||
- name: zhios-mall-container | |||
image: registry-vpc.cn-shenzhen.aliyuncs.com/fnuoos-prd/zyos-mall:0.1 | |||
ports: | |||
- containerPort: 5002 | |||
name: 5002tcp | |||
protocol: TCP | |||
resources: | |||
limits: | |||
cpu: "1" | |||
memory: 256Mi | |||
requests: | |||
cpu: 200m | |||
memory: 128Mi | |||
imagePullPolicy: IfNotPresent | |||
restartPolicy: Always | |||
volumes: | |||
- name: host-time | |||
hostPath: | |||
path: /etc/localtime | |||
type: '' | |||
- name: mall-cfg | |||
configMap: | |||
name: zhios-mall-cfg | |||
defaultMode: 420 | |||
selector: | |||
matchLabels: | |||
app: zhios-mall | |||
strategy: | |||
type: RollingUpdate | |||
rollingUpdate: | |||
maxUnavailable: 25% | |||
maxSurge: 25% |
@@ -1,7 +1,9 @@ | |||
package main | |||
import ( | |||
"applet/app/db" | |||
"context" | |||
"errors" | |||
"fmt" | |||
"log" | |||
"net/http" | |||
@@ -11,69 +13,57 @@ import ( | |||
"time" | |||
"applet/app/cfg" | |||
"applet/app/db" | |||
"applet/app/router" | |||
"applet/app/utils" | |||
) | |||
//系统初始化 | |||
// 系统初始化 | |||
func init() { | |||
cfg.InitCfg() //配置初始化 | |||
cfg.InitLog() //日志初始化 | |||
cfg.InitCache() //缓存初始化 | |||
if cfg.Debug { //判断是否是debug | |||
if err := db.InitDB(cfg.DB); err != nil { //主数据库初始化 | |||
cfg.InitCfg() // 配置初始化 | |||
cfg.InitLog() // 日志初始化 | |||
cfg.InitCache() // 缓存初始化 | |||
cfg.InitMq() // 队列初始化 | |||
if cfg.Debug { // 判断是否是debug | |||
if err := db.InitDB(cfg.DB); err != nil { // 主数据库初始化 | |||
panic(err) | |||
} | |||
channel := make(chan int, 0) //开辟管道,缓冲为 | |||
go db.InitDBs(channel) | |||
<-channel | |||
} | |||
fmt.Println("init success") | |||
} | |||
// @title 智莺生活移动端接口 | |||
// @title 蛋蛋星球-管理后台 | |||
// @version 1.0 | |||
// @description 移动端接口 | |||
// @termsOfService 智莺生活后端组 | |||
// @contact.name sherlockwhite | |||
// @host localhost:5000 | |||
// @description 管理后台接口文档 | |||
// @termsOfService http://swagger.io/terms/ | |||
// @contact.name dengbiao | |||
// @contact.url http://www.swagger.io/support | |||
// @contact.email 1239118001@qq.com | |||
// @license.name Apache 2.0 | |||
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html | |||
// @host localhost:4001 | |||
// @securityDefinitions.apikey MasterID | |||
// @in header | |||
// @name MasterID | |||
// @BasePath / | |||
// @BasePath /api | |||
func main() { | |||
// 启动获取所有品牌 | |||
//go taoke.GetAllBrand() | |||
r := router.Init() //创建路由 | |||
// arkid.Init() | |||
srv := &http.Server{ //设置http服务参数 | |||
Addr: cfg.SrvAddr, //指定ip和端口 | |||
Handler: r, //指定路由 | |||
} | |||
// 读取默认站长的推广位 并写进redis | |||
// master, err := db.UserProfileFindByID(,"1") | |||
r := router.Init() // 创建路由 | |||
// if err != nil { | |||
// panic(err) | |||
// } | |||
if cfg.CurlDebug { | |||
utils.CurlDebug = true | |||
srv := &http.Server{ // 设置http服务参数 | |||
Addr: cfg.SrvAddr, // 指定ip和端口 | |||
Handler: r, // 指定路由 | |||
} | |||
// | |||
// if has := cache.SetJson(svc.SysCfgGet(nil, "app_name")+"_default_pid_user", master, 0); has != true { | |||
// panic(errors.New("设置默认pid缓存失败")) | |||
// } | |||
// Initializing the server in a goroutine so that it won't block the graceful shutdown handling below | |||
go func() { //协程启动监听http服务 | |||
go func() { // 协程启动监听http服务 | |||
fmt.Println("Listening and serving HTTP on " + cfg.SrvAddr) | |||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { | |||
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) { | |||
log.Fatalf("listen: %s\n", err) | |||
} | |||
}() | |||
// graceful shutdown | |||
//退出go守护进程 | |||
// 退出go守护进程 | |||
quit := make(chan os.Signal) | |||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) | |||
<-quit | |||