@@ -0,0 +1,6 @@ | |||
/_build | |||
/**/node_modules* | |||
/web/adm/dist | |||
/*.exe | |||
/conf/curs | |||
/_data |
@@ -0,0 +1,15 @@ | |||
{ | |||
// 使用 IntelliSense 了解相关属性。 | |||
// 悬停以查看现有属性的描述。 | |||
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 | |||
"version": "0.2.0", | |||
"configurations": [ | |||
{ | |||
"name": "Launch Package", | |||
"type": "go", | |||
"request": "launch", | |||
"mode": "auto", | |||
"program": "${workspaceRoot}/" | |||
} | |||
] | |||
} |
@@ -0,0 +1,13 @@ | |||
{ | |||
"prettier.trailingComma": "all", | |||
"editor.wordWrapColumn": 160, | |||
"typescript.preferences.quoteStyle": "single", | |||
"javascript.preferences.quoteStyle": "single", | |||
"workbench.tree.indent": 30, | |||
"workbench.tree.renderIndentGuides": "always", | |||
"prettier.singleQuote": true, | |||
"prettier.jsxBracketSameLine": true, | |||
"prettier.jsxSingleQuote": true, | |||
"prettier.printWidth": 160, | |||
"compile-hero.disable-compile-files-on-did-save-code": true | |||
} |
@@ -0,0 +1,51 @@ | |||
package api | |||
import ( | |||
"fmt" | |||
"strconv" | |||
"strings" | |||
"time" | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
jwt "3g3e.com/rechy/ck.ba.api/jwt-v2" | |||
"3g3e.com/ymdx/lib" | |||
"github.com/gin-gonic/gin" | |||
) | |||
// | |||
func Unauthorized(c *gin.Context, code int, message string) { | |||
baapi.JSONReply(c, "nologin", fmt.Sprintf(message)) | |||
} | |||
// | |||
func GetUserId(c *gin.Context) (baapi.Type, int64) { | |||
claims := jwt.ExtractClaims(c) | |||
fmt.Println(lib.JsonEncodeIndent(claims)) | |||
r := strings.Split(claims["id"].(string), "-") | |||
if len(r) < 2 { | |||
return baapi.TypeUnknown, 0 | |||
} | |||
id, _ := strconv.ParseInt(r[1], 10, 64) | |||
return baapi.Type(r[0]), id | |||
} | |||
// 登录 | |||
func LoginResponse(c *gin.Context, code int, token string, tm time.Time) { | |||
user, ok := c.Get("user") | |||
if !ok { | |||
baapi.JSONReply(c, "error", "用户信息不存在") | |||
return | |||
} | |||
dd := gin.H{ | |||
"token": token, | |||
"user": user, | |||
} | |||
baapi.JSONReply(c, "success", "登录成功", dd) | |||
} | |||
// 登出 | |||
func LogoutResponse(c *gin.Context, code int) { | |||
baapi.JSONReply(c, "success", "退出成功") | |||
} |
@@ -0,0 +1,28 @@ | |||
package pub | |||
import ( | |||
"sync" | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
) | |||
// 命令对应方法的键值对集 | |||
// cmd => func(*baapi.Command) (string, string, interface{}) | |||
var fns sync.Map | |||
func FindHandler(cmd string) (func(*baapi.Command) (string, interface{}, interface{}), bool) { | |||
r, ok := fns.Load(cmd) | |||
if !ok { | |||
return nil, false | |||
} | |||
f, ok := r.(func(*baapi.Command) (string, interface{}, interface{})) | |||
if !ok { | |||
return nil, false | |||
} | |||
return f, true | |||
} | |||
func RegisterCommand(cmd string, fn func(*baapi.Command) (string, interface{}, interface{})) { | |||
fns.Store(cmd, fn) | |||
} |
@@ -0,0 +1,39 @@ | |||
package pub | |||
import ( | |||
"encoding/json" | |||
"3g3e.com/gaotianwang/ck.platform.tag/models" | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
"3g3e.com/ymdx/glog" | |||
) | |||
func init() { | |||
RegisterCommand("close_module", CommandCloseModule) | |||
} | |||
// 关闭模块 | |||
func CommandCloseModule(req *baapi.Command) (string, interface{}, interface{}) { | |||
glog.Infolns("run pub command:", req) | |||
if req.Data == "" { | |||
return "error", "req.Data is empty", nil | |||
} | |||
//将商户的开启状态修改成禁止状态 | |||
var userinfo *baapi.ModUser | |||
err := json.Unmarshal([]byte(req.Data), &userinfo) | |||
if err != nil { | |||
return "error", err, nil | |||
} | |||
uuid := userinfo.UUID | |||
info := make(map[string]interface{}) | |||
info["status"] = 11 | |||
re := models.Db.Table("euser").Where("uuid = ?", uuid).Updates(info) | |||
if re.Error != nil { | |||
return "fail", "商户更新失败", nil | |||
} | |||
return "success", "成功", nil | |||
} |
@@ -0,0 +1,42 @@ | |||
package pub | |||
import ( | |||
"net/http" | |||
"strconv" | |||
"time" | |||
"github.com/gin-gonic/gin" | |||
) | |||
const Imgfile = "/var/www/soft/ck.platform.tag/img/" | |||
const Imgpath = "https://dx.3g3e.com.cn/img/" | |||
func UpFile(c *gin.Context) { | |||
//获取文件头 | |||
file, err := c.FormFile("file") | |||
if err != nil { | |||
c.JSON(http.StatusOK, gin.H{ | |||
"message": "error", | |||
"msg": err.Error(), | |||
}) | |||
return | |||
} | |||
//获取文件名 | |||
t := time.Now().Unix() | |||
fileName := strconv.FormatInt(t, 10) + ".png" | |||
path := Imgfile + fileName | |||
//保存文件到服务器本地 | |||
//SaveUploadedFile(文件头,保存路径) | |||
if err := c.SaveUploadedFile(file, path); err != nil { | |||
c.JSON(http.StatusOK, gin.H{ | |||
"message": "error", | |||
"msg": "上传失败", | |||
}) | |||
return | |||
} | |||
//保存成功返回正确的Json数据 | |||
c.JSON(http.StatusOK, gin.H{ | |||
"message": "ok", | |||
"picture": Imgpath + fileName, | |||
}) | |||
} |
@@ -0,0 +1,33 @@ | |||
package api | |||
import ( | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
"3g3e.com/ymdx/glog" | |||
"github.com/gin-gonic/gin" | |||
) | |||
// @Summary 测试 | |||
// @Accept json | |||
// @Produce json | |||
// @Param param1 query string false "参数1" | |||
// @Param param2 query string false "参数2" | |||
// @Success 200 {object} baapi.ResponseMessage "{code:success, message:...}" | |||
// @Failure 203 {object} baapi.ResponseMessage "{code:error, message:...}" | |||
// @Router /api/test [get] | |||
func Test(c *gin.Context) { | |||
var req struct { | |||
Param1 string `form:"param1" json:"param1" binding:"-"` | |||
Param2 string `form:"param2" json:"param2" binding:"-"` | |||
} | |||
if err := c.ShouldBind(&req); err != nil { | |||
baapi.JSONReply(c, "error", err, nil) | |||
return | |||
} | |||
glog.Infolns(req) | |||
baapi.JSONReply("success", "测试成功", gin.H{ | |||
"test": "测试内容", | |||
}) | |||
} |
@@ -0,0 +1,15 @@ | |||
:: 删除目录 | |||
rd /s /q _build | |||
md _build | |||
:: 编译主程序 | |||
set GOOS=linux | |||
set GOARCH=amd64 | |||
::go build -ldflags "-s -w" -o "_build/ck.platform.tag" | |||
go build -o "_build/ck.platform.tag" | |||
:: 构建目录 | |||
::echo F | xcopy /y /c /q .\conf\app_svr.conf .\_build\conf\app.conf | |||
::echo F | xcopy /y /c /q .\conf\default_svr.conf .\_build\conf\default.conf | |||
::xcopy /y /e /c /i /q .\static .\_build\static | |||
::xcopy /y /e /c /i /q .\views .\_build\views |
@@ -0,0 +1,49 @@ | |||
package common | |||
import ( | |||
"github.com/jmoiron/sqlx" | |||
) | |||
func Rows(rows *sqlx.Rows) []map[string]interface{} { | |||
res := make([]map[string]interface{}, 0) | |||
if rows == nil { | |||
return res | |||
} | |||
for rows.Next() { | |||
dest := make(map[string]interface{}) | |||
rows.MapScan(dest) | |||
for key, item := range dest { | |||
switch item.(type) { | |||
case []byte: | |||
dest[key] = string(item.([]byte)) | |||
default: | |||
} | |||
} | |||
res = append(res, dest) | |||
} | |||
rows.Close() | |||
return res | |||
} | |||
func SqlInStrFromArrayString(items []string) string { | |||
ll := len(items) | |||
str := "" | |||
for i := 0; i < ll; i++ { | |||
idStr := items[i] | |||
if idStr == "" { | |||
continue | |||
} | |||
if i > 0 { | |||
str = str + "','" + idStr | |||
} else { | |||
str = "('" + idStr | |||
} | |||
} | |||
if len(str) > 0 { | |||
str = str + "')" | |||
} else { | |||
str = "(-1)" | |||
} | |||
return str | |||
} |
@@ -0,0 +1,29 @@ | |||
{ | |||
"cors_domain_perttens": [ | |||
"*.3g3e.com.cn", | |||
"3g3e.com.cn", | |||
"*.3g3e.com", | |||
"3g3e.com" | |||
], | |||
"db": { | |||
"driver": "mysql", | |||
"source": "cktag01:WLrijWppwE9@tcp(221.180.226.54:3389)/ck_tag?charset=utf8mb4\u0026parseTime=True\u0026loc=Local" | |||
}, | |||
"id": "Olg37J0dQy12vxlx", | |||
"module": { | |||
"ba_login_url": "https://ba.3g3e.com.cn/api/login", | |||
"ba_url": "https://ba.3g3e.com.cn", | |||
"jwt": { | |||
"ba": { | |||
"others": null, | |||
"public_key": "" | |||
}, | |||
"self": { | |||
"private_key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAKCAQEA8ApSX+Jc+V0/w35fA5oj19Ot8u0wvO6rb4pf7qouOwS2M3yy\nc1E4YC98S5ltuj3uVQpOLBhD/OjEWQGPmEeu65IKIKIenVu9Y1WtTwt0iCf34Jwx\nxrwB3daWrNRgb2JR7fS76YCSL6ydjJWhngGn+QdFesb/hR2Zv7fhO89yrbg1+tm2\n2gLSghvqJUWLrohLeKiJKKT5YTldL1753oEAU4X4lHA+MAu5GHLZdwhXBFrmT8Ii\nAez0vxFb6zfGVmBUaR2NTqd03Yqf70rLaxGP4PN/mSiJvbTXPA79LXAS0pCPFwcY\nX2XoPiuAEdebYGf1FqAGtFwKxlRiuxxxHBdGewIDAQABAoIBAHLU/UNRjxjcOzzS\nn7Ghc7Q0V+r2/XHk266oi+wpDaS+REutQ9FW8ZlSHiwsYgnOxs13+J2vnhbHY+cQ\nkBlRcaTQYHfsFqlA0gFLY3WFDWJ1fGe/UTC5kEsH9V0I3Hlsl7U2dw7lqwmTkmtG\nyeJE+I5xpBNwT5zm5D6LQPzT6RChOj9rQ5j2v7BVozfP2maKsCCOZqY+w8FagRZW\nBYPUhf+l1PwptsUZ54YnEN2EZ30cRUT9De8Q/h/hcmNi0qTCavLnS+3jpOHnDtxK\nTH313JvbNb91IGpo88ih8Pc8arSbW763DiINu8PuxPmVQombOUCx1Tvp3OxrBUHS\nsGG9kQECgYEA+tSKpur1Gvk1GO/tG/huH5yR8uLgwq7cSRop/xd8pQH9oopf5Gk4\nkyxjAZGUQtqaT6fiPQoEZqDj0GkrJ7RnW2zo5Nzhi4BNF8Ma5AkEApo2y0cztKQb\nDXSz1l2T9y68vj0csYn7ULdEuAXze6vVGgEVI+FLr3Fvf0YD74KDKDECgYEA9PzZ\nZCppr6NhEo1PZ1z13NukmvAVhjGPrwWJaResjEbJ0SgOwk2DzvoeKDS2VywCBcJx\nJf8JkOts9HE4ApR5h7zCSY2rXi5v47pR7j1jPAAwo6Qb5X/zS4/qZDSsmjompGow\n2GvCAvgmh3B4Tr89Uy5GUGOhbozxBl2UeIyYmmsCgYEAkTRHS9fKqqHHtjb2qXGI\ntq4Z42SpvqohhgQqeazsEE31uYmnd3/eK3zPl9Hh5U3NdP14P+OzpoHPQBAR1nte\nNhP3Qr4Hp41Pk8jzoT0C4ErMG6ONcC5sJr7/eMJVbQvWYb7ZBIIfRZvCoVF4oYhY\n5iPoTAwZl2fwptouXxHLwZECgYEArsrktCHKrAUOknT+LUpXJRAVPnKDeO5NjNuP\nccrxUliDT9abySgTHg64i4koe8OrYb6cijaP9bTzVOiexMB4gU8888u/c///1uQt\n5qQn9DxSd770JGeJB+WTn5ExgQxyW6ZkWVVw5Dt3CfVF8TFjKMEAbATZvg2TPi5w\nax4tFycCgYEAp3t3ZkOE4XHy/835wQbDQoSZc0eIlDoXmCSKwfVJmMUmQ3cIz0VC\n94ZNeim5N/bvoeZLNTx4wzLzzVdkiCoPIOElomwYlLf5Dv5t8N5qBnw+DPHHe783\nW/3xSo5wJ/WKJ3zef6wBqyuL2IS9+urgAyfs2llaQZXrrOwowmGbIEA=\n-----END RSA PRIVATE KEY-----\n", | |||
"public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ApSX+Jc+V0/w35fA5oj\n19Ot8u0wvO6rb4pf7qouOwS2M3yyc1E4YC98S5ltuj3uVQpOLBhD/OjEWQGPmEeu\n65IKIKIenVu9Y1WtTwt0iCf34JwxxrwB3daWrNRgb2JR7fS76YCSL6ydjJWhngGn\n+QdFesb/hR2Zv7fhO89yrbg1+tm22gLSghvqJUWLrohLeKiJKKT5YTldL1753oEA\nU4X4lHA+MAu5GHLZdwhXBFrmT8IiAez0vxFb6zfGVmBUaR2NTqd03Yqf70rLaxGP\n4PN/mSiJvbTXPA79LXAS0pCPFwcYX2XoPiuAEdebYGf1FqAGtFwKxlRiuxxxHBdG\newIDAQAB\n-----END PUBLIC KEY-----\n" | |||
} | |||
}, | |||
"key": "ck.tag.api" | |||
}, | |||
"port": 8350 | |||
} |
@@ -0,0 +1,367 @@ | |||
package db | |||
import ( | |||
"errors" | |||
"math" | |||
"strings" | |||
"3g3e.com/gaotianwang/ck.platform.tag/common" | |||
"3g3e.com/ymdx/glog" | |||
"3g3e.com/ymdx/lib" | |||
"github.com/jmoiron/sqlx" | |||
) | |||
var sdb *sqlx.DB | |||
func InitDB(dirverName, dataSource string) (*sqlx.DB, error) { | |||
if sdb != nil { | |||
sdb.Close() | |||
sdb = nil | |||
} | |||
if dirverName == "sqlite3" && dataSource != ":memory:" { | |||
dataSource = lib.EnsureFilePath(dataSource) | |||
} | |||
var err error | |||
sdb, err = sqlx.Open(dirverName, dataSource) | |||
if err != nil { | |||
glog.Infoln(err) | |||
return nil, err | |||
} | |||
sdb.SetMaxOpenConns(300) | |||
sdb.SetMaxIdleConns(30) | |||
sdb.Ping() | |||
//create table | |||
return sdb, nil | |||
} | |||
func PayOrderFld(sess map[string]interface{}, utype string, muid int, uid int, cpnum float64, orderId string, about string) error { | |||
if utype == "user" { | |||
sql := "SELECT user_money FROM user WHERE uid=? LIMIT 0, 1" | |||
rows, err := sdb.Queryx(sql, muid) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return err | |||
} | |||
rs := common.Rows(rows) | |||
rows.Close() | |||
if len(rs) == 0 { | |||
return errors.New("1#len(rs) == 0") | |||
} | |||
mone := rs[0] | |||
if cpnum == 0 { | |||
about = "您已成功获得此次充值!" | |||
} | |||
if cpnum < 0 { | |||
needMoney := lib.ValueToFloat(mone["user_money"], 0.0) - math.Abs(cpnum/10000) | |||
wtime := lib.Now().Format("2006-01-02 15:04:05") | |||
sqli := "INSERT INTO paycouponlog (uid,order_sn,muid,user_money,cpcr,type_desc,cpabout,status,now_count,wtime) VALUES (?,?,?,?,?,?,?,?,?,?)" | |||
_, err := sdb.Exec(sqli, | |||
uid, | |||
orderId, | |||
muid, | |||
cpnum/10000, | |||
"", | |||
"获得充值", | |||
about, | |||
1, | |||
needMoney, | |||
wtime) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return err | |||
} | |||
DecUserMoney(muid, math.Abs(cpnum), about, needMoney, sess) | |||
} else { | |||
needMoney := lib.ValueToFloat(mone["user_money"], 0.0) + math.Abs(cpnum/10000) | |||
wtime := lib.Now().Format("2006-01-02 15:04:05") | |||
sqli := "INSERT INTO paycouponlog (uid,order_sn,muid,user_money,cpcr,type_desc,cpabout,status,now_count,wtime) VALUES (?,?,?,?,?,?,?,?,?,?)" | |||
_, err := sdb.Exec(sqli, | |||
uid, | |||
orderId, | |||
muid, | |||
cpnum/10000, | |||
"", | |||
"获得充值", | |||
about, | |||
1, | |||
needMoney, | |||
wtime) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return err | |||
} | |||
AddUserMoney(muid, cpnum, about, needMoney, sess) | |||
} | |||
} else if utype == "euser" { | |||
sql := "SELECT user_money FROM euser WHERE uid=? LIMIT 0, 1" | |||
rows, err := sdb.Queryx(sql, muid) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return err | |||
} | |||
rs := common.Rows(rows) | |||
rows.Close() | |||
if len(rs) == 0 { | |||
return errors.New("2#len(rs) == 0") | |||
} | |||
mone := rs[0] | |||
if cpnum == 0 { | |||
about = "您已成功获得此次充值!" | |||
} | |||
if cpnum < 0 { | |||
needMoney := lib.ValueToFloat(mone["user_money"], 0.0) - math.Abs(cpnum/10000) | |||
wtime := lib.Now().Format("2006-01-02 15:04:05") | |||
sqli := "INSERT INTO epaycouponlog (uid,order_sn,muid,user_money,cpcr,type_desc,cpabout,status,now_count,wtime) VALUES (?,?,?,?,?,?,?,?,?,?)" | |||
_, err := sdb.Exec(sqli, | |||
uid, | |||
orderId, | |||
muid, | |||
cpnum/10000, | |||
"", | |||
"获得充值", | |||
about, | |||
1, | |||
needMoney, | |||
wtime, | |||
) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return err | |||
} | |||
DecEuserMoney(muid, math.Abs(cpnum), about, needMoney, sess) | |||
} else { | |||
needMoney := lib.ValueToFloat(mone["user_money"], 0.0) + math.Abs(cpnum/10000) | |||
wtime := lib.Now().Format("2006-01-02 15:04:05") | |||
sqli := "INSERT INTO epaycouponlog (uid,order_sn,muid,user_money,cpcr,type_desc,cpabout,status,now_count,wtime) VALUES (?,?,?,?,?,?,?,?,?,?)" | |||
_, err := sdb.Exec(sqli, | |||
uid, | |||
orderId, | |||
muid, | |||
cpnum/10000, | |||
"", | |||
"获得充值", | |||
about, | |||
1, | |||
needMoney, | |||
wtime, | |||
) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return err | |||
} | |||
AddEuserMoney(muid, cpnum, about, needMoney, sess) | |||
} | |||
} | |||
return nil | |||
} | |||
func AddUserMoney(uid int, num float64, title string, now_count float64, sess map[string]interface{}) bool { | |||
re := false | |||
if !lib.ValueIsEmpty(uid) && num >= 0 { | |||
re = AddPayLog( | |||
uid, | |||
num, | |||
title, | |||
now_count, | |||
sess, | |||
) | |||
} | |||
return re | |||
} | |||
func DecUserMoney(uid int, num float64, title string, now_count float64, sess map[string]interface{}) bool { | |||
re := false | |||
if !lib.ValueIsEmpty(uid) && num >= 0 { | |||
re = AddPayLog( | |||
uid, | |||
(-1)*num, | |||
title, | |||
now_count, | |||
sess, | |||
) | |||
} | |||
return re | |||
} | |||
func AddPayLog(userId int, userMoney float64, changeDesc string, now_count float64, sess map[string]interface{}) bool { | |||
if userMoney < 0 { | |||
gcount := GetCount("SELECT COUNT(*) FROM user Where uid = ? and user_money >= ?", userId, math.Abs(userMoney/10000)) | |||
if gcount == 0 { | |||
return false | |||
} | |||
} | |||
/* 插入帐户变动记录 */ | |||
changeTime := lib.Now().Format("2006-01-02 15:04:05") | |||
sql := "INSERT INTO payaccountlog (user_id,user_money,change_desc,change_time,change_type,now_count) VALUES (?,?,?,?,?,?)" | |||
_, err := sdb.Exec(sql, | |||
userId, | |||
userMoney/10000, | |||
changeDesc, | |||
changeTime, | |||
99, | |||
now_count, | |||
) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return false | |||
} | |||
/* 更新用户信息 */ | |||
sqli := "UPDATE user SET user_money=user_money+? WHERE uid=?" | |||
_, err = sdb.Exec(sqli, | |||
userMoney/10000, | |||
userId, | |||
) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return false | |||
} | |||
if sess != nil { | |||
sqls := "SELECT user_money FROM user WHERE uid=? LIMIT 0, 1" | |||
rows, err := sdb.Queryx(sqls, userId) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return false | |||
} | |||
rs := common.Rows(rows) | |||
rows.Close() | |||
if len(rs) == 0 { | |||
glog.Errorln("#重大错误") | |||
return false | |||
} | |||
mone := rs[0] | |||
sess["user_money"] = mone["user_money"] | |||
} | |||
return true | |||
} | |||
func AddEPayLog(userId int, userMoney float64, changeDesc string, now_count float64, sess map[string]interface{}) bool { | |||
if userMoney < 0 && userId != 1 { | |||
gcount := GetCount("SELECT COUNT(*) FROM euser Where uid = ? and user_money >= ?", userId, math.Abs(userMoney/10000)) | |||
if gcount == 0 { | |||
return false | |||
} | |||
} | |||
/* 插入帐户变动记录 */ | |||
changeTime := lib.Now().Format("2006-01-02 15:04:05") | |||
sql := "INSERT INTO epayaccountlog (user_id,user_money,change_desc,change_time,change_type,now_count) VALUES (?,?,?,?,?,?)" | |||
_, err := sdb.Exec(sql, | |||
userId, | |||
userMoney/10000, | |||
changeDesc, | |||
changeTime, | |||
99, | |||
now_count, | |||
) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return false | |||
} | |||
/* 更新用户信息 */ | |||
sqli := "UPDATE euser SET user_money=user_money+?,sys_money=sys_money+? WHERE uid=?" | |||
_, err = sdb.Exec(sqli, | |||
userMoney/10000, | |||
userMoney/10000, | |||
userId, | |||
) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return false | |||
} | |||
if sess != nil { | |||
sqls := "SELECT user_money FROM euser WHERE uid=? LIMIT 0, 1" | |||
rows, err := sdb.Queryx(sqls, userId) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return false | |||
} | |||
rs := common.Rows(rows) | |||
rows.Close() | |||
if len(rs) == 0 { | |||
glog.Errorln("#重大错误") | |||
return false | |||
} | |||
mone := rs[0] | |||
sess["user_money"] = mone["user_money"] | |||
sess["sys_money"] = mone["sys_money"] | |||
} | |||
return true | |||
} | |||
func GetCount(sql string, args ...interface{}) int { | |||
strings.Replace(sql, "count(*)", "COUNT(*)", -1) | |||
rows, err := sdb.Queryx(sql, args...) | |||
if err != nil { | |||
return 0 | |||
} | |||
rs := common.Rows(rows) | |||
rows.Close() | |||
if len(rs) == 0 { | |||
return 0 | |||
} | |||
return lib.ValueToInt(rs[0]["COUNT(*)"], 0) | |||
} | |||
func DecEuserMoney(uid int, num float64, title string, now_count float64, sess map[string]interface{}) bool { | |||
re := false | |||
if !lib.ValueIsEmpty(uid) && num >= 0 { | |||
re = AddEPayLog( | |||
uid, | |||
(-1)*num, | |||
title, | |||
now_count, | |||
sess, | |||
) | |||
} | |||
return re | |||
} | |||
func AddEuserMoney(uid int, num float64, title string, now_count float64, sess map[string]interface{}) bool { | |||
re := false | |||
if !lib.ValueIsEmpty(uid) && num >= 0 { | |||
re = AddEPayLog( | |||
uid, | |||
num, | |||
title, | |||
now_count, | |||
sess, | |||
) | |||
} | |||
return re | |||
} | |||
func GETEuser(eid int64) (map[string]interface{}, error) { | |||
sql := "SELECT user_money FROM euser WHERE uid=? LIMIT 0, 1" | |||
rows, err := sdb.Queryx(sql, eid) | |||
if err != nil { | |||
glog.Errorln(err) | |||
return nil, err | |||
} | |||
rs := common.Rows(rows) | |||
rows.Close() | |||
if len(rs) == 0 { | |||
return nil, errors.New("2#len(rs) == 0") | |||
} | |||
sess := rs[0] | |||
return sess, nil | |||
} |
@@ -0,0 +1,76 @@ | |||
module 3g3e.com/gaotianwang/ck.platform.tag | |||
go 1.22 | |||
toolchain go1.22.4 | |||
replace ( | |||
3g3e.com/rechy/ck.ba.api => ./../../../3g3e.com/rechy/ck.ba.api | |||
3g3e.com/rechy/visdb => ./../../../3g3e.com/rechy/visdb | |||
3g3e.com/ymdx/config => ./../../../3g3e.com/ymdx/config | |||
3g3e.com/ymdx/glog => ./../../../3g3e.com/ymdx/glog | |||
3g3e.com/ymdx/lib => ./../../../3g3e.com/ymdx/lib | |||
) | |||
require ( | |||
3g3e.com/rechy/ck.ba.api v0.0.0-00010101000000-000000000000 | |||
3g3e.com/rechy/visdb v0.0.0-00010101000000-000000000000 | |||
3g3e.com/ymdx/config v0.0.0-00010101000000-000000000000 | |||
3g3e.com/ymdx/glog v0.0.0-00010101000000-000000000000 | |||
3g3e.com/ymdx/lib v0.0.0-00010101000000-000000000000 | |||
github.com/dgrijalva/jwt-go v3.2.0+incompatible | |||
github.com/gin-gonic/gin v1.10.0 | |||
github.com/jmoiron/sqlx v1.4.0 | |||
github.com/satori/go.uuid v1.2.0 | |||
github.com/takama/daemon v1.0.0 | |||
github.com/unknwon/com v1.0.1 | |||
golang.org/x/crypto v0.26.0 | |||
gorm.io/driver/mysql v1.5.7 | |||
gorm.io/gorm v1.25.11 | |||
) | |||
require ( | |||
filippo.io/edwards25519 v1.1.0 // indirect | |||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 // indirect | |||
github.com/bmatcuk/doublestar/v2 v2.0.4 // indirect | |||
github.com/bytedance/sonic v1.11.6 // indirect | |||
github.com/bytedance/sonic/loader v0.1.1 // indirect | |||
github.com/cloudwego/base64x v0.1.4 // indirect | |||
github.com/cloudwego/iasm v0.2.0 // indirect | |||
github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3 // indirect | |||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect | |||
github.com/gin-contrib/pprof v1.5.0 // indirect | |||
github.com/gin-contrib/sse v0.1.0 // indirect | |||
github.com/go-playground/locales v0.14.1 // indirect | |||
github.com/go-playground/universal-translator v0.18.1 // indirect | |||
github.com/go-playground/validator/v10 v10.20.0 // indirect | |||
github.com/go-sql-driver/mysql v1.8.1 // indirect | |||
github.com/goccy/go-json v0.10.2 // indirect | |||
github.com/gofrs/flock v0.8.1 // indirect | |||
github.com/gookit/color v1.5.2 // indirect | |||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 // indirect | |||
github.com/hunzsig/graphics v0.0.0-20190929035859-45587367f25f // indirect | |||
github.com/jinzhu/inflection v1.0.0 // indirect | |||
github.com/jinzhu/now v1.1.5 // indirect | |||
github.com/json-iterator/go v1.1.12 // indirect | |||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect | |||
github.com/kr/text v0.1.0 // indirect | |||
github.com/leodido/go-urn v1.4.0 // indirect | |||
github.com/mattn/go-isatty v0.0.20 // indirect | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | |||
github.com/modern-go/reflect2 v1.0.2 // indirect | |||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect | |||
github.com/rogpeppe/go-internal v1.12.0 // indirect | |||
github.com/smartystreets/assertions v1.1.0 // indirect | |||
github.com/smartystreets/goconvey v1.6.4 // indirect | |||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | |||
github.com/ugorji/go/codec v1.2.12 // indirect | |||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect | |||
golang.org/x/arch v0.8.0 // indirect | |||
golang.org/x/net v0.25.0 // indirect | |||
golang.org/x/sys v0.23.0 // indirect | |||
golang.org/x/text v0.17.0 // indirect | |||
google.golang.org/protobuf v1.34.1 // indirect | |||
gopkg.in/yaml.v2 v2.4.0 // indirect | |||
gopkg.in/yaml.v3 v3.0.1 // indirect | |||
) |
@@ -0,0 +1,173 @@ | |||
filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= | |||
filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= | |||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412 h1:w1UutsfOrms1J05zt7ISrnJIXKzwaspym5BTKGx93EI= | |||
github.com/agl/ed25519 v0.0.0-20170116200512-5312a6153412/go.mod h1:WPjqKcmVOxf0XSf3YxCJs6N6AOSrOx3obionmG7T0y0= | |||
github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4= | |||
github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw= | |||
github.com/bmatcuk/doublestar/v2 v2.0.4 h1:6I6oUiT/sU27eE2OFcWqBhL1SwjyvQuOssxT4a1yidI= | |||
github.com/bmatcuk/doublestar/v2 v2.0.4/go.mod h1:QMmcs3H2AUQICWhfzLXz+IYln8lRQmTZRptLie8RgRw= | |||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= | |||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= | |||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= | |||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU= | |||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= | |||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= | |||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg= | |||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY= | |||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | |||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | |||
github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3 h1:l/lhv2aJCUignzls81+wvga0TFlyoZx8QxRMQgXpZik= | |||
github.com/decred/dcrd/dcrec/edwards/v2 v2.0.3/go.mod h1:AKpV6+wZ2MfPRJnTbQ6NPgWrKzbe9RCIlCF/FKzMtM8= | |||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM= | |||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= | |||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= | |||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= | |||
github.com/gin-contrib/pprof v1.5.0 h1:E/Oy7g+kNw94KfdCy3bZxQFtyDnAX2V7axRS7sNYVrU= | |||
github.com/gin-contrib/pprof v1.5.0/go.mod h1:GqFL6LerKoCQ/RSWnkYczkTJ+tOAUVN/8sbnEtaqOKs= | |||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | |||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= | |||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU= | |||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= | |||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s= | |||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= | |||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= | |||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= | |||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= | |||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= | |||
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8= | |||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= | |||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= | |||
github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= | |||
github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= | |||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= | |||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= | |||
github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= | |||
github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= | |||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= | |||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | |||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= | |||
github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI= | |||
github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= | |||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00 h1:l5lAOZEym3oK3SQ2HBHWsJUfbNBiTXJDeW2QDxw9AQ0= | |||
github.com/gopherjs/gopherjs v0.0.0-20200217142428-fce0ec30dd00/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= | |||
github.com/hunzsig/graphics v0.0.0-20190929035859-45587367f25f h1:qXExBWlmgjia7C3PTdsg52SA4LmJ+0Y0tyIWZ/SToA0= | |||
github.com/hunzsig/graphics v0.0.0-20190929035859-45587367f25f/go.mod h1:gv/HT+LsUPuRTgdXpYU3BYHzw0rzxMKpp70IZMUnrhE= | |||
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= | |||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= | |||
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= | |||
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= | |||
github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= | |||
github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= | |||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= | |||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= | |||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= | |||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= | |||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= | |||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM= | |||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= | |||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= | |||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= | |||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= | |||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= | |||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= | |||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= | |||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= | |||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= | |||
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= | |||
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= | |||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= | |||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | |||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= | |||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= | |||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= | |||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= | |||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= | |||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= | |||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= | |||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= | |||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | |||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | |||
github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= | |||
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= | |||
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= | |||
github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww= | |||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= | |||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v0.0.0-20190116191733-b6c0e53d7304/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= | |||
github.com/smartystreets/assertions v1.1.0 h1:MkTeG1DMwsrdH7QtLXy5W+fUxWq+vmb6cLmyJ7aRtF0= | |||
github.com/smartystreets/assertions v1.1.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo= | |||
github.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s= | |||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s= | |||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= | |||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= | |||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= | |||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= | |||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= | |||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= | |||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= | |||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= | |||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= | |||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | |||
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= | |||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= | |||
github.com/takama/daemon v1.0.0 h1:XS3VLnFKmqw2Z7fQ/dHRarrVjdir9G3z7BEP8osjizQ= | |||
github.com/takama/daemon v1.0.0/go.mod h1:gKlhcjbqtBODg5v9H1nj5dU1a2j2GemtuWSNLD5rxOE= | |||
github.com/tidwall/gjson v1.17.1 h1:wlYEnwqAHgzmhNUFfw7Xalt2JzQvsMx2Se4PcoFCT/U= | |||
github.com/tidwall/gjson v1.17.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= | |||
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= | |||
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= | |||
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= | |||
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= | |||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= | |||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= | |||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= | |||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= | |||
github.com/unknwon/com v1.0.1 h1:3d1LTxD+Lnf3soQiD4Cp/0BRB+Rsa/+RTvz8GMMzIXs= | |||
github.com/unknwon/com v1.0.1/go.mod h1:tOOxU81rwgoCLoOVVPHb6T/wt8HZygqH5id+GNnlCXM= | |||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= | |||
github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= | |||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= | |||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc= | |||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= | |||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | |||
golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= | |||
golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= | |||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | |||
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac= | |||
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM= | |||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
golang.org/x/sys v0.0.0-20200722175500-76b94024e4b6/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | |||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||
golang.org/x/sys v0.23.0 h1:YfKFowiIMvtgl1UERQoTPPToxltDeZfbj4H7dVUCwmM= | |||
golang.org/x/sys v0.23.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= | |||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= | |||
golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= | |||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= | |||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | |||
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= | |||
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= | |||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | |||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= | |||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= | |||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= | |||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= | |||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | |||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= | |||
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo= | |||
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM= | |||
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= | |||
gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= | |||
gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= | |||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= | |||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= |
@@ -0,0 +1,179 @@ | |||
package keys | |||
import ( | |||
"crypto/rsa" | |||
"errors" | |||
"sync" | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
jwt "3g3e.com/rechy/ck.ba.api/jwt-v2" | |||
cfg "3g3e.com/ymdx/config" | |||
"3g3e.com/ymdx/glog" | |||
"3g3e.com/ymdx/lib" | |||
) | |||
var km *KeyManager | |||
var keyManagerLock sync.Mutex | |||
func GetKeyManager() *KeyManager { | |||
keyManagerLock.Lock() | |||
defer keyManagerLock.Unlock() | |||
if km == nil { | |||
km = &KeyManager{} | |||
} | |||
if !km.isInited { | |||
km.initKeys() | |||
} | |||
return km | |||
} | |||
func ResetKeyManager() error { | |||
keyManagerLock.Lock() | |||
defer keyManagerLock.Unlock() | |||
k := &KeyManager{} | |||
err := k.initKeys() | |||
if err != nil { | |||
return err | |||
} | |||
km = k | |||
return nil | |||
} | |||
type BaKeys struct { | |||
MyPrivateKey *rsa.PrivateKey | |||
AimPublicKey *rsa.PublicKey | |||
} | |||
type KeyManager struct { | |||
isInited bool | |||
selfPrivateKey *rsa.PrivateKey | |||
selfPublicKey *rsa.PublicKey | |||
baPrivKeys sync.Map // string(module_name) => *BaKeys | |||
baOtherPublicKeys sync.Map // string(module_name) => *rsa.PublicKey | |||
baPublicKey *rsa.PublicKey | |||
} | |||
func (k *KeyManager) initKeys() error { | |||
defer func() { | |||
// 不管是否成功初始化, 都设置为已经初始化 | |||
k.isInited = true | |||
}() | |||
var err error | |||
privKey, pubKey, err := lib.GenKeyPair(2048) | |||
if err != nil { | |||
return err | |||
} | |||
selfPrivateKey := cfg.String("module.jwt.self.private_key", privKey) | |||
selfPublicKey := cfg.String("module.jwt.self.public_key", pubKey) | |||
baPublicKey := cfg.String("module.jwt.ba.public_key", "") | |||
baOtherPublicKeys := cfg.Map("module.jwt.ba.others", nil) | |||
k.selfPrivateKey, err = jwt.ParseRSAPrivateKeyFromPEM([]byte(selfPrivateKey)) | |||
if err != nil { | |||
return err | |||
} | |||
k.selfPublicKey, err = jwt.ParseRSAPublicKeyFromPEM([]byte(selfPublicKey)) | |||
if err != nil { | |||
return err | |||
} | |||
for ki, vi := range baOtherPublicKeys { | |||
pkey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(lib.ValueToString(vi, ""))) | |||
if err != nil { | |||
glog.Errorlns("ba.others.public_key:", ki, err) | |||
continue | |||
} | |||
k.baOtherPublicKeys.Store(ki, pkey) | |||
} | |||
k.baPublicKey, err = jwt.ParseRSAPublicKeyFromPEM([]byte(baPublicKey)) | |||
if err != nil { | |||
return err | |||
} | |||
return nil | |||
} | |||
func (k *KeyManager) ModifyTokenHeader(header map[string]interface{}) map[string]interface{} { | |||
header["iss"] = baapi.ModuleName() | |||
return header | |||
} | |||
func (k *KeyManager) KeyFuncVerify(header map[string]interface{}) (interface{}, error) { | |||
iss, ok1 := header["iss"] // 颁发模块 | |||
aud, ok2 := header["aud"] // token申请登录模块 | |||
if ok1 && ok2 && iss != "" && aud != "" { | |||
if iss == aud { | |||
return k.selfPublicKey, nil | |||
} | |||
} | |||
if k.baPublicKey == nil { | |||
return nil, jwt.ErrInvalidPubKey | |||
} | |||
s, ok := k.baOtherPublicKeys.Load(aud) | |||
if ok { | |||
return s.(*rsa.PublicKey), nil | |||
} | |||
return k.baPublicKey, nil | |||
} | |||
func (k *KeyManager) KeyFuncSign(header map[string]interface{}) (interface{}, error) { | |||
iss, ok1 := header["iss"] | |||
aud, ok2 := header["aud"] | |||
if ok1 && ok2 && iss != "" && aud != "" { | |||
if iss == aud { | |||
if k.selfPrivateKey != nil { | |||
return k.selfPrivateKey, nil | |||
} | |||
} else { | |||
ks, ok := k.baPrivKeys.Load(aud) | |||
if ok && ks != nil { | |||
keys := ks.(*BaKeys) | |||
if keys.MyPrivateKey != nil { | |||
return keys.MyPrivateKey, nil | |||
} | |||
} | |||
} | |||
} | |||
return nil, jwt.ErrInvalidPrivKey | |||
} | |||
func (k *KeyManager) Sign(isBA bool, moduleTo string, data string) (string, error) { | |||
if isBA { | |||
ks, ok := k.baPrivKeys.Load(moduleTo) | |||
if ok && ks != nil { | |||
keys := ks.(*BaKeys) | |||
if keys.MyPrivateKey != nil { | |||
return jwt.RS512Sign(data, keys.MyPrivateKey) | |||
} | |||
} | |||
} else { | |||
return jwt.RS512Sign(string(data), k.selfPrivateKey) | |||
} | |||
return "", errors.New("sign fail") | |||
} | |||
func (k *KeyManager) Verify(isBA bool, moduleFrom string, data string, sign string) error { | |||
if isBA { | |||
ks, ok := k.baPrivKeys.Load(moduleFrom) | |||
if ok && ks != nil { | |||
keys := ks.(*BaKeys) | |||
if keys.AimPublicKey != nil { | |||
return jwt.RS512Verify(data, sign, keys.AimPublicKey) | |||
} | |||
} | |||
} else { | |||
return jwt.RS512Verify(data, sign, k.baPublicKey) | |||
} | |||
return errors.New("verify fail") | |||
} |
@@ -0,0 +1,54 @@ | |||
package keys | |||
import ( | |||
"path/filepath" | |||
"sync" | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
"3g3e.com/rechy/visdb" | |||
"3g3e.com/ymdx/lib" | |||
) | |||
func TokenSaverInitBySyncMap() { | |||
baapi.ModTokenSaver = &sync.Map{} | |||
} | |||
func TokenSaverInit(baseDir string) { | |||
baapi.ModTokenSaver = newVisdbTokenSaver(baseDir) | |||
} | |||
type visdbTokenSaver struct { | |||
kv *visdb.KV | |||
baseDir string | |||
} | |||
func newVisdbTokenSaver(baseDir string) *visdbTokenSaver { | |||
return &visdbTokenSaver{ | |||
kv: visdb.NewKV(filepath.Join(baseDir, "db_pub_token_saver"), 3), | |||
baseDir: baseDir, | |||
} | |||
} | |||
func (ts *visdbTokenSaver) Store(k interface{}, v interface{}) { | |||
ts.kv.Put(lib.ValueToString(k, ""), v) | |||
} | |||
func (ts *visdbTokenSaver) Load(k interface{}) (interface{}, bool) { | |||
b, err := ts.kv.Get(lib.ValueToString(k, "")) | |||
if err != nil { | |||
return nil, false | |||
} | |||
return b, true | |||
} | |||
func (ts *visdbTokenSaver) Delete(k interface{}) { | |||
ts.kv.Delete(lib.ValueToString(k, "")) | |||
} | |||
func Store(k interface{}, v interface{}) { | |||
baapi.ModTokenSaver.Store(k, v) | |||
} | |||
func Load(k interface{}) (interface{}, bool) { | |||
return baapi.ModTokenSaver.Load(k) | |||
} |
@@ -0,0 +1,42 @@ | |||
package main | |||
import ( | |||
"fmt" | |||
"3g3e.com/gaotianwang/ck.platform.tag/models" | |||
"3g3e.com/gaotianwang/ck.platform.tag/routers" | |||
cfg "3g3e.com/ymdx/config" | |||
"3g3e.com/ymdx/glog" | |||
"github.com/gin-gonic/gin" | |||
) | |||
const ( | |||
srvName = "Platform Tag Mnaager" | |||
srvDescription = "Platform Tag Mnaager by Change Ke" | |||
) | |||
var ( | |||
ServicePort int = 8350 | |||
) | |||
func (app *exitApp) main() { | |||
defer app.exit() | |||
defer glog.Flush() | |||
// defer glog.Defer("") | |||
// 开始链接数据库 | |||
err := models.Init() | |||
if err != nil { | |||
glog.Errorln("数据库连接失败:", err) | |||
return | |||
} | |||
r := gin.Default() | |||
routers.SetupRouter(r) | |||
ServicePort = cfg.Int("port", ServicePort) | |||
err = r.Run(fmt.Sprintf(":%d", ServicePort)) | |||
if err != nil { | |||
glog.Errorln("服务器异常退出:", err) | |||
return | |||
} | |||
} |
@@ -0,0 +1,88 @@ | |||
package models | |||
import ( | |||
"context" | |||
"fmt" | |||
"time" | |||
sdb "3g3e.com/gaotianwang/ck.platform.tag/db" | |||
cfg "3g3e.com/ymdx/config" | |||
"3g3e.com/ymdx/glog" | |||
"gorm.io/driver/mysql" | |||
"gorm.io/gorm" | |||
"gorm.io/gorm/logger" | |||
) | |||
var Db *gorm.DB | |||
var tables []interface{} | |||
type dbLogger struct{} | |||
func (w *dbLogger) LogMode(logger.LogLevel) logger.Interface { | |||
return w | |||
} | |||
func (w *dbLogger) Info(ctx context.Context, format string, args ...interface{}) { | |||
glog.InfoExtDepthln("db", -4, fmt.Sprintf(format, args...)) | |||
} | |||
func (w *dbLogger) Warn(ctx context.Context, format string, args ...interface{}) { | |||
glog.WarningExtDepthln("db", -4, fmt.Sprintf(format, args...)) | |||
} | |||
func (w *dbLogger) Error(ctx context.Context, format string, args ...interface{}) { | |||
glog.ErrorExtDepthln("db", -4, fmt.Sprintf(format, args...)) | |||
} | |||
func (w *dbLogger) Trace(ctx context.Context, begin time.Time, fc func() (sql string, rowsAffected int64), err error) { | |||
sql, affw := fc() | |||
glog.InfoExtDepthln("db", -4, sql, affw, err) | |||
} | |||
func Init() error { | |||
driver := cfg.String("db.driver", "mysql") | |||
glog.InfoExtln("db", driver) | |||
source := cfg.String("db.source", "ckdx01:WAdijEspwEE@tcp(221.180.226.54:3389)/ck_dx?charset=utf8&parseTime=True&loc=Local") | |||
db, err := gorm.Open(mysql.New(mysql.Config{ | |||
DSN: source, | |||
}), &gorm.Config{ | |||
Logger: &dbLogger{}, | |||
}) | |||
if err != nil { | |||
return err | |||
} | |||
Db = db | |||
sdb.InitDB(driver, source) | |||
Db.AutoMigrate(tables...) | |||
//Db.DB().SetMaxIdleConns(10) | |||
//Db.DB().SetMaxOpenConns(100) | |||
return nil | |||
} | |||
func CloseDB() { | |||
} | |||
func SqlInStrFromArrayString(items []string) string { | |||
ll := len(items) | |||
str := "" | |||
for i := 0; i < ll; i++ { | |||
idStr := items[i] | |||
if idStr == "" { | |||
continue | |||
} | |||
if i > 0 { | |||
str = str + "','" + idStr | |||
} else { | |||
str = "('" + idStr | |||
} | |||
} | |||
if len(str) > 0 { | |||
str = str + "')" | |||
} else { | |||
str = "(-1)" | |||
} | |||
return str | |||
} |
@@ -0,0 +1,100 @@ | |||
package tpl | |||
import ( | |||
"bytes" | |||
"errors" | |||
"regexp" | |||
"strings" | |||
"3g3e.com/ymdx/lib" | |||
) | |||
func TemplateToContent(template, paramsJsonStr string, contents ...string) (string, error) { | |||
template = strings.TrimSpace(template) | |||
if template == "" { | |||
return "", errors.New("empty template") | |||
} | |||
if template == "*" { | |||
if len(contents) < 1 || contents[0] == "" { | |||
return "", errors.New("no sms content") | |||
} | |||
return strings.TrimSpace(contents[0]), nil | |||
} | |||
params := lib.JsonDecode([]byte(paramsJsonStr)) | |||
r := regexp.MustCompile(`\$\{([a-zA-Z0-9_]+)\}`) | |||
tpl := []byte(template) | |||
arr := r.FindAllSubmatchIndex(tpl, -1) | |||
pre := 0 | |||
buf := bytes.NewBuffer(nil) | |||
for _, v := range arr { | |||
if len(v) < 4 { | |||
continue | |||
} | |||
buf.Write(tpl[pre:v[0]]) | |||
key := template[v[2]:v[3]] | |||
val, ok := params[string(key)] | |||
if !ok { | |||
return "", errors.New("lost var") | |||
} | |||
pre = v[1] | |||
valStr := lib.ValueToString(val, "") | |||
if valStr == "" { | |||
return "", errors.New("unknown sms var value") | |||
} | |||
buf.WriteString(valStr) | |||
} | |||
buf.Write(tpl[pre:]) | |||
return buf.String(), nil | |||
} | |||
// 模板变量返回 | |||
func TemplateVars(template string) ([]string, error) { | |||
r := regexp.MustCompile(`\$\{([a-zA-Z0-9_]+)\}`) | |||
arr := r.FindAllStringSubmatch(template, -1) | |||
sz := len(arr) | |||
if sz < 1 { | |||
return nil, nil | |||
} | |||
mp := map[string]string{} | |||
re := make([]string, 0) | |||
for _, v := range arr { | |||
if len(v) < 2 { | |||
continue | |||
} | |||
_, ok := mp[v[1]] | |||
if ok { | |||
return nil, errors.New("vars count error") | |||
} | |||
mp[v[1]] = v[0] | |||
re = append(re, v[1]) | |||
} | |||
return re, nil | |||
} | |||
// 模板书写是否有效 | |||
func TemplateValid(template string) bool { | |||
r := regexp.MustCompile(`\$\{([a-zA-Z0-9_]+)\}`) | |||
arr := r.FindAllStringSubmatch(template, -1) | |||
mp := map[string]string{} | |||
for _, v := range arr { | |||
if len(v) < 2 { | |||
continue | |||
} | |||
mp[v[1]] = v[0] | |||
} | |||
sz := len(mp) | |||
if sz != len(arr) { | |||
return false | |||
} | |||
r2 := regexp.MustCompile(`\$\{`) | |||
arr2 := r2.FindAllString(template, -1) | |||
return sz == len(arr2) | |||
} |
@@ -0,0 +1,83 @@ | |||
package utils | |||
import ( | |||
"encoding/csv" | |||
"net/http" | |||
"net/url" | |||
) | |||
const ( | |||
CsvFlushLineMax = 500 | |||
) | |||
// | |||
type CsvWriter struct { | |||
w *csv.Writer | |||
count int | |||
} | |||
// | |||
func CsvNewWriter(w http.ResponseWriter, filename string) *CsvWriter { | |||
w.Header().Set("Content-Type", "application/csv") | |||
w.Header().Set("Content-Disposition", "attachment; filename=\""+url.QueryEscape(filename)+"\"") | |||
w.Write([]byte("\xEF\xBB\xBF")) | |||
return &CsvWriter{w: csv.NewWriter(w)} | |||
} | |||
// | |||
func (c *CsvWriter) Write(data ...interface{}) error { | |||
if c.w == nil || len(data) < 1 { | |||
return nil | |||
} | |||
dataStrs := make([]string, len(data)) | |||
for k, v := range data { | |||
dataStrs[k] = ValueToString(v, "") | |||
} | |||
c.count++ | |||
err := c.w.Write(dataStrs) | |||
if c.count > CsvFlushLineMax { | |||
c.w.Flush() | |||
c.count = 0 | |||
} | |||
return err | |||
} | |||
// | |||
func (c *CsvWriter) WriteString(data ...string) error { | |||
if c.w == nil || len(data) < 1 { | |||
return nil | |||
} | |||
c.count++ | |||
err := c.w.Write(data) | |||
if c.count > CsvFlushLineMax { | |||
c.w.Flush() | |||
c.count = 0 | |||
} | |||
return err | |||
} | |||
// | |||
func (c *CsvWriter) Close() { | |||
c.w.Flush() | |||
} | |||
func (c *CsvWriter) WriteByMap(data map[string]map[string]string, mapkey []string) { | |||
// if c.w == nil || len(data) < 1 { | |||
// return nil | |||
// } | |||
for _, v := range data { | |||
dataStrs := make([]string, len(v)) | |||
// i := 0 | |||
for i := 0; i < len(mapkey); i++ { | |||
dataStrs[i] = ValueToString(v[mapkey[i]], "") | |||
} | |||
c.w.Write(dataStrs) | |||
} | |||
c.count++ | |||
if c.count > CsvFlushLineMax { | |||
c.w.Flush() | |||
c.count = 0 | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
package utils | |||
import ( | |||
"github.com/gin-gonic/gin" | |||
"github.com/unknwon/com" | |||
) | |||
func GetPage(c *gin.Context) int { | |||
result := 0 | |||
page, _ := com.StrTo(c.Query("pg")).Int() | |||
if page > 0 { | |||
result = (page - 1) * 20 | |||
} | |||
return result | |||
} |
@@ -0,0 +1,337 @@ | |||
package utils | |||
import ( | |||
"fmt" | |||
"math/rand" | |||
"reflect" | |||
"regexp" | |||
"strconv" | |||
"strings" | |||
"time" | |||
"github.com/dgrijalva/jwt-go" | |||
guuid "github.com/satori/go.uuid" | |||
"golang.org/x/crypto/bcrypt" | |||
) | |||
func ValueIsEmpty(str string) bool { | |||
if str == "" || len(str) == 0 { | |||
return true | |||
} | |||
return false | |||
} | |||
func ValueToInt(in interface{}, def int) int { | |||
if in == nil { | |||
return def | |||
} | |||
switch in.(type) { | |||
case int: | |||
return in.(int) | |||
case int8: | |||
return int(in.(int8)) | |||
case int16: | |||
return int(in.(int16)) | |||
case int32: | |||
return int(in.(int32)) | |||
case int64: | |||
return int(in.(int64)) | |||
case uint: | |||
return int(in.(uint)) | |||
case uint8: | |||
return int(in.(uint8)) | |||
case uint16: | |||
return int(in.(uint16)) | |||
case uint32: | |||
return int(in.(uint32)) | |||
case uint64: | |||
return int(in.(uint64)) | |||
case float32: | |||
return int(in.(float32)) | |||
case float64: | |||
return int(in.(float64)) | |||
case []byte: | |||
ii, _ := strconv.ParseFloat(string(in.([]byte)), 64) | |||
return int(ii) | |||
case string: | |||
ii, _ := strconv.ParseFloat(in.(string), 64) | |||
return int(ii) | |||
case *[]byte: | |||
ii, _ := strconv.ParseFloat(string(*(in.(*[]byte))), 64) | |||
return int(ii) | |||
case *string: | |||
ii, _ := strconv.ParseFloat(*(in.(*string)), 64) | |||
return int(ii) | |||
default: | |||
} | |||
return def | |||
} | |||
func ValueToString(in interface{}, def string) string { | |||
return ValueToStringIn(in, def, 0) | |||
} | |||
func ValueToStringIn(in interface{}, def string, fixed int) string { | |||
if in == nil { | |||
return def | |||
} | |||
switch in.(type) { | |||
case int: | |||
return strconv.FormatInt(int64(in.(int)), 10) | |||
case int8: | |||
return strconv.FormatInt(int64(in.(int8)), 10) | |||
case int16: | |||
return strconv.FormatInt(int64(in.(int16)), 10) | |||
case int32: | |||
return strconv.FormatInt(int64(in.(int32)), 10) | |||
case int64: | |||
return strconv.FormatInt(in.(int64), 10) | |||
case uint: | |||
return strconv.FormatUint(uint64(in.(uint)), 10) | |||
case uint8: | |||
return strconv.FormatUint(uint64(in.(uint8)), 10) | |||
case uint16: | |||
return strconv.FormatUint(uint64(in.(uint16)), 10) | |||
case uint32: | |||
return strconv.FormatUint(uint64(in.(uint32)), 10) | |||
case uint64: | |||
return strconv.FormatUint(in.(uint64), 10) | |||
case float32: | |||
if fixed > 0 { | |||
return strconv.FormatFloat(float64(in.(float32)), 'f', fixed, 32) | |||
} | |||
return strconv.FormatFloat(float64(in.(float32)), 'f', 10, 32) | |||
case float64: | |||
if fixed > 0 { | |||
return strconv.FormatFloat(in.(float64), 'f', fixed, 64) | |||
} | |||
return strconv.FormatFloat(in.(float64), 'f', 10, 64) | |||
case []byte: | |||
return string(in.([]byte)) | |||
case string: | |||
return in.(string) | |||
case *[]byte: | |||
return string(*(in.(*[]byte))) | |||
case *string: | |||
return *(in.(*string)) | |||
default: | |||
} | |||
return def | |||
} | |||
// 判断某一个值是否在切片中 | |||
func In_array(val interface{}, array interface{}) (exists bool, index int) { | |||
exists = false | |||
index = -1 | |||
switch reflect.TypeOf(array).Kind() { | |||
case reflect.Slice: | |||
s := reflect.ValueOf(array) | |||
for i := 0; i < s.Len(); i++ { | |||
if reflect.DeepEqual(val, s.Index(i).Interface()) == true { | |||
index = i | |||
exists = true | |||
return | |||
} | |||
} | |||
} | |||
return | |||
} | |||
// 数组转换成string类型 | |||
func ArrayToString(wh []string) string { | |||
whereStr := "" | |||
arrLen := len(wh) | |||
for i := 0; i < arrLen; i++ { | |||
whereStr = whereStr + " " + wh[i] + " AND" | |||
} | |||
whereStr = strings.TrimRight(whereStr, " AND") | |||
return whereStr | |||
} | |||
// 生成随机方案 | |||
func GetOrderNum() string { | |||
// 获取纳秒数 | |||
usec := time.Now().UnixNano() | |||
usecStr := strconv.FormatInt(usec, 10)[13:16] | |||
// 当天凌晨时间 | |||
str := time.Now().Format("2006-01-02") | |||
ti, _ := time.Parse("2006-01-02", str) | |||
// 当前时间和凌晨时间差的秒数 | |||
timeNum := time.Now().Unix() - ti.Unix() | |||
sec := fmt.Sprintf("%05d", timeNum) | |||
// 生成随机数并自动填充 | |||
sn := fmt.Sprintf("%05d", rand.Intn(100000)) | |||
num := time.Now().Format("060102") + sec + usecStr + sn | |||
return num | |||
} | |||
// 数据库中的时间转换 | |||
func StrTimeTostr(str string) string { | |||
time := strings.Replace(str, "T", " ", -1) | |||
time = time[0:19] | |||
return time | |||
} | |||
/** | |||
* 解析 token | |||
*/ | |||
func ParseToken(tokenSrt string, SecretKey []byte) (id string, name string, err error) { | |||
var token *jwt.Token | |||
token, err = jwt.Parse(tokenSrt, func(*jwt.Token) (interface{}, error) { | |||
return SecretKey, nil | |||
}) | |||
if !token.Valid { //服务端验证token是否有效 | |||
if ve, ok := err.(*jwt.ValidationError); ok { | |||
if ve.Errors&jwt.ValidationErrorMalformed != 0 { | |||
fmt.Println("错误的token") | |||
return | |||
} else if ve.Errors&(jwt.ValidationErrorExpired|jwt.ValidationErrorNotValidYet) != 0 { | |||
fmt.Println("token过期或未启用") | |||
return | |||
} else { | |||
fmt.Println("无法处理这个token", err) | |||
return | |||
} | |||
} | |||
} | |||
// token信息 | |||
claimsa, _ := token.Claims.(jwt.MapClaims) | |||
id = claimsa["id"].(string) | |||
name = claimsa["name"].(string) | |||
return | |||
} | |||
// 加密 | |||
// 生成随机ordersn方案 | |||
func GetOrderSn() string { | |||
// 获取纳秒数 | |||
usec := time.Now().UnixNano() | |||
usecStr := strconv.FormatInt(usec, 10)[13:16] | |||
// 当天凌晨时间 | |||
str := time.Now().Format("2006-01-02") | |||
ti, _ := time.Parse("2006-01-02", str) | |||
// 当前时间和凌晨时间差的秒数 | |||
timeNum := time.Now().Unix() - ti.Unix() | |||
sec := fmt.Sprintf("%05d", timeNum) | |||
// 生成随机数并自动填充 | |||
sn := fmt.Sprintf("%05d", rand.Intn(100000)) | |||
num := time.Now().Format("060102") + sec + usecStr + sn | |||
return num | |||
} | |||
// 加密密码 | |||
func GenUserHashPassword(password string) (string, error) { | |||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) | |||
if err != nil { | |||
return "", err | |||
} | |||
return string(hash), nil | |||
} | |||
// 验证密码 | |||
func ComparePasswords(hashedPwd string, plainPwd string) error { | |||
byteHash := []byte(hashedPwd) | |||
bytePlain := []byte(plainPwd) | |||
err := bcrypt.CompareHashAndPassword(byteHash, bytePlain) | |||
return err | |||
} | |||
// 将rune数组用字符串常量替换 | |||
const letterBytes = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |||
// 生成随机数 | |||
func RandStringBytes(n int) string { | |||
// GenRsaKey(1024) | |||
b := make([]byte, n) | |||
for i := range b { | |||
b[i] = letterBytes[rand.Intn(len(letterBytes))] | |||
} | |||
return string(b) | |||
} | |||
func GetOrderSnn() string { | |||
str := guuid.NewV4().String() | |||
return strings.ReplaceAll(str, "-", "") | |||
} | |||
func SplitString(s string, myStrings []rune) []string { | |||
Split := func(r rune) bool { | |||
for _, v := range myStrings { | |||
if v == r { | |||
return true | |||
} | |||
} | |||
return false | |||
} | |||
a := strings.FieldsFunc(s, Split) | |||
return a | |||
} | |||
// 提取模板内容 | |||
func ExtractContent(input string) []string { | |||
// 定义正则表达式模式 | |||
pattern := `\${(.*?)\}` // 非贪婪模式,只匹配最小数量的字符 | |||
// pattern := `/ $ (\w) }/gi` | |||
// 编译正则表达式 | |||
re := regexp.MustCompile(pattern) | |||
// 查找所有匹配项并返回结果切片 | |||
matches := re.FindAllStringSubmatch(input, -1) | |||
var result []string | |||
for _, match := range matches { | |||
re := regexp.MustCompile(`\$|\{|\}`) // 创建正则表达式对象,匹配大括号 | |||
result = append(result, re.ReplaceAllString(match[0], "")) | |||
} | |||
return result | |||
} | |||
// 生成随机数 | |||
func GenValidateCodeNew(width int) string { | |||
numeric := [64]string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"} | |||
r := len(numeric) | |||
rand.Seed(time.Now().UnixNano()) | |||
sb := "" | |||
for i := 0; i < width; i++ { | |||
sb += numeric[rand.Intn(r)] | |||
} | |||
return sb | |||
} | |||
func CheckMobile(phone string) (bool, string) { | |||
// todo | |||
valid := regexp.MustCompile("[0-9]") | |||
num := valid.FindAllString(phone, -1) | |||
phone = strings.Join(num, "") | |||
// 匹配规则 | |||
// ^1第一位为一 | |||
// [345789]{1} 后接一位345789 的数字 | |||
// \\d \d的转义 表示数字 {9} 接9位 | |||
// $ 结束符 | |||
regRuler := "^1[3456789]{1}\\d{9}$" | |||
// 正则调用规则 | |||
reg := regexp.MustCompile(regRuler) | |||
// 返回 MatchString 是否匹配 | |||
return reg.MatchString(phone), phone | |||
} | |||
// 计算时间差(天数) | |||
func SubDays(t1, t2 time.Time) (day int) { | |||
day = int(t1.Sub(t2).Hours() / 24) | |||
return | |||
} |
@@ -0,0 +1,107 @@ | |||
package routers | |||
import ( | |||
"errors" | |||
"fmt" | |||
"time" | |||
"3g3e.com/gaotianwang/ck.platform.tag/api" | |||
"3g3e.com/gaotianwang/ck.platform.tag/keys" | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
jwt "3g3e.com/rechy/ck.ba.api/jwt-v2" | |||
"github.com/gin-gonic/gin" | |||
) | |||
const ( | |||
JwtRealm = "CK" | |||
JwtTokenHeadName = "ChangKe" | |||
) | |||
var identityKey = "id" | |||
func getJwtAuth() (*jwt.GinJWTMiddleware, error) { | |||
authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{ | |||
Realm: JwtRealm, | |||
SigningAlgorithm: baapi.JwtSigningAlgorithm, | |||
Timeout: 30 * time.Minute, | |||
MaxRefresh: 20 * time.Minute, | |||
IdentityKey: identityKey, | |||
// 从data一个用户里找个唯一值做token存储的id | |||
PayloadFunc: func(data interface{}) jwt.MapClaims { | |||
if v, ok := data.(*baapi.ModAuthor); ok { | |||
m := jwt.MapClaims{ | |||
"author": v.String(), | |||
identityKey: fmt.Sprintf("%v-%v", v.Type, v.ID), | |||
} | |||
return m | |||
} | |||
return jwt.MapClaims{} | |||
}, | |||
// 从token存储的id值, 再读取出用户的相关账户信息 | |||
IdentityHandler: func(c *gin.Context) interface{} { | |||
claims := jwt.ExtractClaims(c) | |||
author, _ := claims["author"].(string) | |||
return baapi.NewModAuthor([]byte(author)) | |||
}, | |||
// 登录时验证账号密码是否正常, 返回用户信息, err为nil就是登录成功 | |||
Authenticator: func(c *gin.Context) (interface{}, time.Duration, error) { | |||
return nil, time.Hour * 24 * 3, errors.New("this is ba client") | |||
}, | |||
// 这个方法就是认证当前页面是否有权操作 | |||
Authorizator: func(data interface{}, c *gin.Context) bool { | |||
if v, ok := data.(*baapi.ModAuthor); ok { | |||
return v.HasAuth(c.Request) | |||
} | |||
return false | |||
}, | |||
// 无权操作, 格式化回复内容 | |||
Unauthorized: api.Unauthorized, | |||
// 登录返回 | |||
LoginResponse: api.LoginResponse, | |||
// 出返回 | |||
LogoutResponse: api.LogoutResponse, | |||
ModifyTokenHeader: modifyTokenHeader, | |||
KeyFuncVerify: keyFuncVerify, | |||
KeyFuncSign: keyFuncSign, | |||
TokenLookup: "header: Authorization, query: token, cookie: jwt", | |||
TokenHeadName: JwtTokenHeadName, | |||
TimeFunc: time.Now, | |||
SendCookie: false, | |||
}) | |||
if err != nil { | |||
return nil, err | |||
} | |||
errInit := authMiddleware.MiddlewareInit() | |||
if errInit != nil { | |||
return nil, errInit | |||
} | |||
return authMiddleware, nil | |||
} | |||
func modifyTokenHeader(header map[string]interface{}) map[string]interface{} { | |||
kmgr := keys.GetKeyManager() | |||
return kmgr.ModifyTokenHeader(header) | |||
} | |||
func keyFuncVerify(header map[string]interface{}) (interface{}, error) { | |||
kmgr := keys.GetKeyManager() | |||
return kmgr.KeyFuncVerify(header) | |||
} | |||
func keyFuncSign(header map[string]interface{}) (interface{}, error) { | |||
kmgr := keys.GetKeyManager() | |||
return kmgr.KeyFuncSign(header) | |||
} |
@@ -0,0 +1,28 @@ | |||
package routers | |||
import ( | |||
"3g3e.com/gaotianwang/ck.platform.tag/api/pub" | |||
"3g3e.com/gaotianwang/ck.platform.tag/keys" | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
) | |||
type PubHub struct { | |||
} | |||
func (pb *PubHub) Sign(isBA bool, moduleTo string, data string) (string, error) { | |||
kmgr := keys.GetKeyManager() | |||
return kmgr.Sign(isBA, moduleTo, data) | |||
} | |||
func (pb *PubHub) Verify(isBA bool, moduleFrom string, data string, sign string) error { | |||
kmgr := keys.GetKeyManager() | |||
return kmgr.Verify(isBA, moduleFrom, data, sign) | |||
} | |||
func (pb *PubHub) Exec(req *baapi.Command) (string, interface{}, interface{}) { | |||
fn, ok := pub.FindHandler(req.Cmd) | |||
if !ok { | |||
return "error", "not support command", nil | |||
} | |||
return fn(req) | |||
} |
@@ -0,0 +1,89 @@ | |||
package routers | |||
import ( | |||
"net/http" | |||
"3g3e.com/gaotianwang/ck.platform.tag/api" | |||
"3g3e.com/gaotianwang/ck.platform.tag/api/pub" | |||
"3g3e.com/ymdx/glog" | |||
"strings" | |||
// "3g3e.com/gaotianwang/ck.platform.tag/controllers" | |||
"3g3e.com/gaotianwang/ck.platform.tag/keys" | |||
baapi "3g3e.com/rechy/ck.ba.api" | |||
"3g3e.com/ymdx/lib" | |||
"github.com/gin-gonic/gin" | |||
) | |||
const ( | |||
ApiPathBase = "/" | |||
) | |||
// Cors is 跨域 | |||
func Cors() gin.HandlerFunc { | |||
return func(c *gin.Context) { | |||
if c.Request == nil || !strings.HasPrefix(c.Request.URL.Path, ApiPathBase) { | |||
c.Next() | |||
return | |||
} | |||
origin := c.Request.Header.Get("Origin") //请求头部 | |||
wh := c.Writer.Header() | |||
if origin != "" { | |||
wh.Set("Access-Control-Allow-Origin", origin) | |||
} else { | |||
wh.Set("Access-Control-Allow-Origin", "*") | |||
} | |||
wh.Set("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE, UPDATE") | |||
wh.Set("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma") | |||
wh.Set("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析 | |||
wh.Set("Access-Control-Max-Age", "172800") // 缓存请求信息 单位为秒 | |||
wh.Set("Access-Control-Allow-Credentials", "true") // 设置返回格式是json | |||
//放行所有OPTIONS方法 | |||
if c.Request.Method == "OPTIONS" { | |||
c.JSON(http.StatusOK, "Options Request!") | |||
} | |||
// 处理请求 | |||
c.Next() | |||
} | |||
} | |||
func SetupRouter(router *gin.Engine) { | |||
// store := cookie.NewStore([]byte("secret")) | |||
// router.Use(Cors(), sessions.Sessions("mysession", store)) | |||
/*******初始化操作权限路由范围 ******/ | |||
baapi.InitBind(router, &PubHub{}) | |||
// 初始化密钥管理器 | |||
keys.GetKeyManager() | |||
/**********************/ | |||
authMiddleware, err := getJwtAuth() | |||
if err != nil { | |||
glog.Fatalf("get jwt middleware err [%+v]", err) | |||
return | |||
} | |||
apiGroup := router.Group("/api") | |||
{ | |||
// 无权限验证 | |||
apiGroup.GET("/test", api.Test) | |||
apiGroup.POST("/login", authMiddleware.LoginHandler) | |||
apiGroup.POST("/upfile", pub.UpFile) | |||
} | |||
v1Master := router.Group(baapi.RouteApiMaster) | |||
v1Master.Use(authMiddleware.MiddlewareFunc()) | |||
{ | |||
} | |||
v1Enterprise := router.Group(baapi.RouteApiEnterprise) | |||
v1Enterprise.Use(authMiddleware.MiddlewareFunc()) | |||
{ | |||
} | |||
// 短信回调 | |||
router.StaticFS("/img", newStaticDir(("/img"), lib.EnsureDir("./img"), "")) | |||
router.StaticFS("/fe", newStaticDir(("/fe"), lib.EnsureDir("./web/fe"), "")) | |||
router.StaticFS("/adm", newStaticDir(("/adm"), lib.EnsureDir("./wwwx"), "index.html")) | |||
router.GET("/", func(c *gin.Context) { c.Redirect(http.StatusFound, "/adm/") }) | |||
} |
@@ -0,0 +1,72 @@ | |||
package routers | |||
import ( | |||
"errors" | |||
"net/http" | |||
"os" | |||
"path" | |||
"path/filepath" | |||
"strings" | |||
) | |||
type staticDir struct { | |||
prefix string | |||
dir string | |||
defaultIndex string | |||
} | |||
func newStaticDir(prefix, dir, defaultIndex string) *staticDir { | |||
return &staticDir{ | |||
prefix: prefix, | |||
dir: dir, | |||
defaultIndex: defaultIndex, | |||
} | |||
} | |||
func mapDirOpenError(originalErr error, name string) error { | |||
if os.IsNotExist(originalErr) || os.IsPermission(originalErr) { | |||
return originalErr | |||
} | |||
parts := strings.Split(name, string(filepath.Separator)) | |||
for i := range parts { | |||
if parts[i] == "" { | |||
continue | |||
} | |||
fi, err := os.Stat(strings.Join(parts[:i+1], string(filepath.Separator))) | |||
if err != nil { | |||
return originalErr | |||
} | |||
if !fi.IsDir() { | |||
return os.ErrNotExist | |||
} | |||
} | |||
return originalErr | |||
} | |||
func (d *staticDir) Handler(w http.ResponseWriter, r *http.Request) { | |||
fileServer := http.StripPrefix(d.prefix, http.FileServer(d)) | |||
fileServer.ServeHTTP(w, r) | |||
} | |||
func (d *staticDir) Open(name string) (http.File, error) { | |||
// 无扩展名请求定位至index.html | |||
if d.defaultIndex != "" && name != "/" && path.Ext(name) == "" { | |||
name = "/" + d.defaultIndex | |||
} | |||
if filepath.Separator != '/' && strings.ContainsRune(name, filepath.Separator) { | |||
return nil, errors.New("http: invalid character in file path") | |||
} | |||
dir := d.dir | |||
if dir == "" { | |||
dir = "." | |||
} | |||
fullName := filepath.Join(dir, filepath.FromSlash(path.Clean("/"+name))) | |||
f, err := os.Open(fullName) | |||
// glog.Infoln(fullName) | |||
if err != nil { | |||
return nil, mapDirOpenError(err, fullName) | |||
} | |||
return f, nil | |||
} |
@@ -0,0 +1,129 @@ | |||
package main | |||
import ( | |||
"context" | |||
"flag" | |||
"fmt" | |||
"log" | |||
"os" | |||
"path/filepath" | |||
cfg "3g3e.com/ymdx/config" | |||
"3g3e.com/ymdx/glog" | |||
"3g3e.com/ymdx/lib" | |||
"github.com/takama/daemon" | |||
) | |||
type exitApp struct { | |||
ctx context.Context | |||
exit context.CancelFunc | |||
baseDir string | |||
} | |||
func imain(ctx context.Context, baseDir string) *exitApp { | |||
app := &exitApp{ | |||
ctx: ctx, | |||
baseDir: baseDir, | |||
} | |||
go app.main() | |||
return app | |||
} | |||
func (app *exitApp) WillExit() error { | |||
return nil | |||
} | |||
func (app *exitApp) SetExitCtrl(exit context.CancelFunc) { | |||
app.exit = exit | |||
} | |||
// Service is | |||
type Service struct { | |||
daemon.Daemon | |||
baseDir string | |||
} | |||
// Manage is | |||
func (s *Service) Manage() (string, error) { | |||
usage := "Usage: " + srvName + " install | remove | start | stop | status" | |||
if len(os.Args) > 1 { | |||
command := os.Args[1] | |||
switch command { | |||
case "install": | |||
return s.Install() | |||
case "remove": | |||
return s.Remove() | |||
case "start": | |||
return s.Start() | |||
case "stop": | |||
return s.Stop() | |||
case "status": | |||
return s.Status() | |||
default: | |||
return usage, nil | |||
} | |||
} | |||
/*************** CLI ***************/ | |||
cliLog := &log.Logger{} | |||
glog.LoggerOutput(cliLog, &glog.LogBridgeOptions{ | |||
Prefix: "CLI", | |||
BaseDepth: 3, | |||
ReplaceMap: nil, | |||
ShowHeaderTrace: true, | |||
}) | |||
cli, ctx := lib.NewCLI(s.baseDir, cliLog) | |||
defer cli.Shutdown() | |||
/*************** 性能分析 ***************/ | |||
//go http.ListenAndServe(":6060", nil) | |||
/*************** 核心 ***************/ | |||
// defer cfg.SaveConfig() | |||
defer glog.Flush() | |||
sp := imain(ctx, s.baseDir) | |||
cli.Add(sp) | |||
/************** CLI LOOP **************/ | |||
cli.Loop() | |||
return "Daemon was killed", nil | |||
} | |||
func main() { | |||
baseDir := "" | |||
flag.StringVar(&baseDir, "dir", "./_data", "running in a directory") | |||
flag.Parse() | |||
baseDir = lib.EnsureDir(baseDir) | |||
pathGLogDir := filepath.Join(baseDir, "glog") | |||
pathLogDir := filepath.Join(baseDir, "log") | |||
// 独立于baseDir | |||
confDir := lib.EnsureDir("./conf") | |||
pathConfig := filepath.Join(confDir, "default.conf") | |||
// os.RemoveAll(pathPageDir) | |||
// os.RemoveAll(pathCaptureDir) | |||
// os.RemoveAll(pathGLogDir) | |||
cfg.InitWithFile("json", pathConfig) | |||
glog.DefaultInit(glog.OtherLog, true, pathGLogDir, pathLogDir) | |||
/*************** Service ***************/ | |||
srv, err := daemon.New(srvName, srvDescription, daemon.SystemDaemon) | |||
if err != nil { | |||
glog.Errorln("Error: ", err) | |||
os.Exit(1) | |||
} | |||
s := &Service{srv, baseDir} | |||
status, err := s.Manage() | |||
if err != nil { | |||
glog.Errorln(status, "\nError: ", err) | |||
os.Exit(1) | |||
} | |||
fmt.Println(status) | |||
} |
@@ -0,0 +1,59 @@ | |||
package main | |||
import ( | |||
"log" | |||
"sync" | |||
"time" | |||
) | |||
type TaskRow struct { | |||
Id int | |||
Phone string | |||
} | |||
func main() { | |||
log.SetFlags(log.Flags() | log.Ldate) | |||
ch := make(chan *TaskRow, 10000) | |||
stopCh := make(chan interface{}) | |||
go func() { | |||
for i := 0; i < 100000; i++ { | |||
ch <- &TaskRow{Id: i, Phone: "139000000"} | |||
} | |||
}() | |||
go func() { | |||
time.Sleep(time.Second * 15) | |||
close(stopCh) | |||
}() | |||
wg := &sync.WaitGroup{} | |||
for i := 0; i < 20; i++ { | |||
wg.Add(1) | |||
go oneThread(i, wg, ch, stopCh) | |||
} | |||
log.Println("开始等待============", time.Now()) | |||
time.Sleep(time.Second * 2) | |||
// wg.Wait() | |||
log.Println("20 线程已经退出============", time.Now()) | |||
} | |||
func oneThread(threadId int, wg *sync.WaitGroup, ch chan *TaskRow, stopCh chan interface{}) { | |||
defer wg.Done() | |||
for { | |||
select { | |||
case <-stopCh: | |||
return | |||
case task := <-ch: | |||
// dealOneTask(task) | |||
log.Println("工人ID:", threadId, "任务: ", task.Id) | |||
// time.Sleep(time.Second * 10) | |||
} | |||
} | |||
} |