From 6488275b8ebe3e429bbbd247c27d21e3e2a2afb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B4=BE=E6=81=A9=E7=BA=B3=E7=89=B9?= <1101839859@qq.com> Date: Thu, 24 Oct 2024 13:51:24 +0800 Subject: [PATCH 1/2] =?UTF-8?q?chores:=20API=E6=89=93=E5=BA=95=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- utils/web/middleware/checkauth.go | 1 + utils/web/response/common.go | 16 ++++++ utils/web/response/response.go | 84 +++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 utils/web/middleware/checkauth.go create mode 100644 utils/web/response/common.go create mode 100644 utils/web/response/response.go diff --git a/utils/web/middleware/checkauth.go b/utils/web/middleware/checkauth.go new file mode 100644 index 00000000..c870d7c1 --- /dev/null +++ b/utils/web/middleware/checkauth.go @@ -0,0 +1 @@ +package middleware diff --git a/utils/web/response/common.go b/utils/web/response/common.go new file mode 100644 index 00000000..33af9638 --- /dev/null +++ b/utils/web/response/common.go @@ -0,0 +1,16 @@ +package response + +// PageInfo 请求分页固定参数 +type PageInfo struct { + Page int `json:"page" form:"page"` // 页码 + PageSize int `json:"pageSize" form:"pageSize"` // 每页大小 + Keyword string `json:"keyword" form:"keyword"` // 关键字 +} + +// 响应分页通用参数 +type PageResult struct { + List interface{} `json:"list"` + Total int64 `json:"total"` + Page int `json:"page"` + PageSize int `json:"pageSize"` +} diff --git a/utils/web/response/response.go b/utils/web/response/response.go new file mode 100644 index 00000000..5c8212be --- /dev/null +++ b/utils/web/response/response.go @@ -0,0 +1,84 @@ +package response + +import ( + "fmt" + "net/http" + + "github.com/labstack/echo/v4" + + log "sealdice-core/utils/kratos" +) + +type Response struct { + Code int `json:"code"` + Data interface{} `json:"data"` + Msg string `json:"msg"` +} + +var logger = log.NewCustomHelper(log.LOG_API, false, nil) + +const ( + ERROR = 400 + SUCCESS = 200 + SUCCESS_TEXT = "获取成功" +) + +func GetGenericErrorMsg(err error) string { + return fmt.Sprintf("执行失败,原因为:%v ,请反馈开发者", err) +} + +func Result(code int, data interface{}, msg string, c echo.Context) error { + // 返回JSON响应 + err := c.JSON(http.StatusOK, Response{ + Code: code, + Data: data, + Msg: msg, + }) + if err != nil { + logger.Debug("Error: ", err) + return err + } + return nil +} + +func NoAuth(message string, c echo.Context) error { + err := c.JSON(http.StatusUnauthorized, Response{ + Code: 7, + Data: nil, + Msg: message, + }) + if err != nil { + logger.Debug("Error: ", err) + return err + } + return nil +} + +func Ok(c echo.Context) error { + return Result(SUCCESS, map[string]interface{}{}, "操作成功", c) +} + +func OkWithMessage(message string, c echo.Context) error { + return Result(SUCCESS, map[string]interface{}{}, message, c) +} + +func OkWithData(data interface{}, c echo.Context) error { + return Result(SUCCESS, data, SUCCESS_TEXT, c) +} + +func OkWithDetailed(data interface{}, message string, c echo.Context) error { + return Result(SUCCESS, data, message, c) +} + +func Fail(c echo.Context) error { + return Result(ERROR, map[string]interface{}{}, "操作失败", c) +} + +func FailWithMessage(message string, c echo.Context) error { + return Result(ERROR, map[string]interface{}{}, message, c) +} + +// 必要性不强,大部分情况下,我们不需要返回所谓data,只需要展示给用户提示信息即可 +// func FailWithDetailed(data interface{}, message string, c echo.Context) { +// Result(ERROR, data, message, c) +// } From 424200b79f3812b8deb9d49a5f1363ede2004af7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B4=BE=E6=81=A9=E7=BA=B3=E7=89=B9?= <1101839859@qq.com> Date: Fri, 25 Oct 2024 16:07:09 +0800 Subject: [PATCH 2/2] =?UTF-8?q?init:=20=E5=88=9D=E7=89=88=20with=20base=20?= =?UTF-8?q?and=20login.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/v2/bind.go | 50 ++++++ api/v2/enter.go | 19 +++ api/v2/middleware/middleware.go | 34 ++++ api/v2/model/README.MD | 5 + api/v2/model/base.go | 30 ++++ api/v2/ui/base.go | 248 ++++++++++++++++++++++++++++++ api/v2/ui/enter.go | 17 ++ api/v2/ui/login.go | 77 ++++++++++ main.go | 4 + utils/kratos/const.go | 1 + utils/web/middleware/checkauth.go | 1 - utils/web/response/response.go | 19 +-- 12 files changed, 492 insertions(+), 13 deletions(-) create mode 100644 api/v2/bind.go create mode 100644 api/v2/enter.go create mode 100644 api/v2/middleware/middleware.go create mode 100644 api/v2/model/README.MD create mode 100644 api/v2/model/base.go create mode 100644 api/v2/ui/base.go create mode 100644 api/v2/ui/enter.go create mode 100644 api/v2/ui/login.go delete mode 100644 utils/web/middleware/checkauth.go diff --git a/api/v2/bind.go b/api/v2/bind.go new file mode 100644 index 00000000..4028026e --- /dev/null +++ b/api/v2/bind.go @@ -0,0 +1,50 @@ +package v2 + +import ( + "runtime" + + "github.com/labstack/echo/v4" + + "sealdice-core/api/v2/middleware" + "sealdice-core/dice" +) + +var ApiGroupApp *ApiGroup + +// Dice 由于现在还不能将配置拆出,导致middleware中间件没法正经做,只能在这里保存一下Dice进行控制。 +var diceInstance *dice.Dice + +// 统一格式:前带/后不带/。 + +// InitBaseRouter 初始化基础路由 +func InitBaseRouter(router *echo.Group) { + publicRouter := router.Group("/base") + baseApi := ApiGroupApp.SystemApiGroup.BaseApi + { + publicRouter.GET("/preinfo", baseApi.PreInfo) + publicRouter.GET("/baseInfo", baseApi.BaseInfo, middleware.AuthMiddleware(diceInstance)) + publicRouter.GET("/heartbeat", baseApi.HeartBeat, middleware.AuthMiddleware(diceInstance)) + publicRouter.GET("/checkSecurity", baseApi.CheckSecurity, middleware.AuthMiddleware(diceInstance)) + // 安卓专属停止代码 + if runtime.GOOS == "android" { + publicRouter.GET("/force_stop", baseApi.ForceStop, middleware.AuthMiddleware(diceInstance)) + } + } +} + +func InitLoginRouter(router *echo.Group) { + publicRouter := router.Group("/login") + loginApi := ApiGroupApp.SystemApiGroup.LoginApi + { + publicRouter.POST("/signin", loginApi.DoSignIn) + publicRouter.GET("/salt", loginApi.DoSignInGetSalt) + } +} + +func InitRouter(router *echo.Echo, dice *dice.Dice) { + diceInstance = dice + ApiGroupApp = InitSealdiceAPIV2(dice) + group := router.Group("/v2/sd-api") + InitBaseRouter(group) + InitLoginRouter(group) +} diff --git a/api/v2/enter.go b/api/v2/enter.go new file mode 100644 index 00000000..de3fad24 --- /dev/null +++ b/api/v2/enter.go @@ -0,0 +1,19 @@ +package v2 + +import ( + "sealdice-core/api/v2/ui" + "sealdice-core/dice" +) + +// 有概率以后支持WEBHOOK等等和UI无关代码 +type ApiGroup struct { + SystemApiGroup ui.WebUIDiceGroup +} + +// InitSealdiceAPIV2 初始化SealdiceAPI V2 +// 先初始化,然后再执行router绑定的代码,这样的好处是任何一块代码都可插拔。 +func InitSealdiceAPIV2(d *dice.Dice) *ApiGroup { + a := new(ApiGroup) + a.SystemApiGroup.Init(d) + return a +} diff --git a/api/v2/middleware/middleware.go b/api/v2/middleware/middleware.go new file mode 100644 index 00000000..65276bc8 --- /dev/null +++ b/api/v2/middleware/middleware.go @@ -0,0 +1,34 @@ +package middleware + +import ( + "github.com/labstack/echo/v4" + + "sealdice-core/dice" + "sealdice-core/utils/web/response" +) + +// AuthMiddleware 鉴权中间件,接收Dice参数,仅允许可用Token. +func AuthMiddleware(d *dice.Dice) echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + authToken := c.Request().Header.Get("Authorization") + // 这里统一使用Dice的目的是,以后考虑直接把DiceManager扬了,改单例模式 + if d.Parent.AccessTokens[authToken] { + return next(c) + } + return response.NoAuth(c) + } + } +} + +func TestModeMiddleware(d *dice.Dice) echo.MiddlewareFunc { + return func(next echo.HandlerFunc) echo.HandlerFunc { + return func(c echo.Context) error { + if d.Parent.JustForTest { + // TODO:补充更多细节,比如”展示模式不能进行xxx操作“ + return response.FailWithMessage("展示模式,无法进行……", c) + } + return next(c) + } + } +} diff --git a/api/v2/model/README.MD b/api/v2/model/README.MD new file mode 100644 index 00000000..acdacffb --- /dev/null +++ b/api/v2/model/README.MD @@ -0,0 +1,5 @@ +# model + +此处存放可能用在API里的所有对应结构。 + +目前考量:除非有必要,否则尽量不把复杂返回结构体写在函数里,否则根本没法看。 diff --git a/api/v2/model/base.go b/api/v2/model/base.go new file mode 100644 index 00000000..4202b66a --- /dev/null +++ b/api/v2/model/base.go @@ -0,0 +1,30 @@ +package model + +// VersionDetail 版本号详细信息 +type VersionDetail struct { + Major uint64 `json:"major"` + Minor uint64 `json:"minor"` + Patch uint64 `json:"patch"` + Prerelease string `json:"prerelease"` + BuildMetaData string `json:"buildMetaData"` +} + +type BaseInfoResponse struct { + AppName string `json:"appName"` + AppChannel string `json:"appChannel"` + Version string `json:"version"` + VersionSimple string `json:"versionSimple"` + VersionDetail VersionDetail `json:"versionDetail"` + VersionNew string `json:"versionNew"` + VersionNewNote string `json:"versionNewNote"` + VersionCode int64 `json:"versionCode"` + VersionNewCode int64 `json:"versionNewCode"` + MemoryAlloc uint64 `json:"memoryAlloc"` + Uptime int64 `json:"uptime"` + MemoryUsedSys uint64 `json:"memoryUsedSys"` + ExtraTitle string `json:"extraTitle"` + OS string `json:"OS"` + Arch string `json:"arch"` + JustForTest bool `json:"justForTest"` + ContainerMode bool `json:"containerMode"` +} diff --git a/api/v2/ui/base.go b/api/v2/ui/base.go new file mode 100644 index 00000000..53ecd5bd --- /dev/null +++ b/api/v2/ui/base.go @@ -0,0 +1,248 @@ +package ui + +import ( + "os" + "runtime" + "runtime/debug" + "strings" + "time" + + "github.com/jmoiron/sqlx" + "github.com/labstack/echo/v4" + + "sealdice-core/api/v2/model" + "sealdice-core/dice" + "sealdice-core/utils/web/response" +) + +// TODO: 注释现在不一定对的上地址,这个还得接着改喵 + +var startTime = time.Now().Unix() + +type fStopEcho struct { + Key string `json:"key"` +} + +// BaseApi +// 曾经这里直接嵌入了Dice,但是后来考虑到这个东西应该是和BaseApi分开 +// BaseApi不应该能用Dice的方法(而是通过方法控制Dice) +type BaseApi struct { + dice *dice.Dice +} + +// PreInfo +// @Tags Base +// @Summary 获取测试模式信息 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Success 200 {object} response.Result{data=map[string]interface{},msg=string} "返回测试模式信息" +// @Router /base/preInfo [post] +func (b *BaseApi) PreInfo(c echo.Context) error { + return response.OkWithData(map[string]interface{}{ + "testMode": b.dice.Parent.JustForTest, + }, c) +} + +// BaseInfo +// @Tags Base +// @Summary 获取基础信息 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Success 200 {object} response.Result{data=model.BaseInfoResponse,msg=string} "返回基础信息,包括应用名称、版本、内存使用等" +// @Router /base/baseinfo [get] +func (b *BaseApi) BaseInfo(c echo.Context) error { + // 鉴权后使用 + dm := b.dice.Parent + var m runtime.MemStats + runtime.ReadMemStats(&m) + + var versionNew string + var versionNewNote string + var versionNewCode int64 + if dm.AppVersionOnline != nil { + versionNew = dm.AppVersionOnline.VersionLatestDetail + versionNewNote = dm.AppVersionOnline.VersionLatestNote + versionNewCode = dm.AppVersionOnline.VersionLatestCode + } + + extraTitle := b.getName() + + versionDetail := model.VersionDetail{ + Major: dice.VERSION.Major(), + Minor: dice.VERSION.Minor(), + Patch: dice.VERSION.Patch(), + Prerelease: dice.VERSION.Prerelease(), + BuildMetaData: dice.VERSION.Metadata(), + } + infoResponse := model.BaseInfoResponse{ + AppName: dice.APPNAME, + AppChannel: dice.APP_CHANNEL, + Version: dice.VERSION.String(), + VersionSimple: dice.VERSION_MAIN + dice.VERSION_PRERELEASE, + VersionDetail: versionDetail, + VersionNew: versionNew, + VersionNewNote: versionNewNote, + VersionCode: dice.VERSION_CODE, + VersionNewCode: versionNewCode, + MemoryAlloc: m.Alloc, + MemoryUsedSys: m.Sys - m.HeapReleased, + Uptime: time.Now().Unix() - startTime, + ExtraTitle: extraTitle, + OS: runtime.GOOS, + Arch: runtime.GOARCH, + JustForTest: dm.JustForTest, + ContainerMode: dm.ContainerMode, + } + + return response.OkWithData(infoResponse, c) +} + +// ForceStop +// @Tags Base +// @Summary 安卓专属:强制停止程序 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Param key body fStopEcho true "强制停止的密钥" +// @Success 200 {object} response.Result{msg=string} "执行成功" +// @Failure 400 {object} response.Result{msg=string} "参数绑定错误/执行错误/Key不匹配等等" +// @Router /base/force-stop [post] +func (b *BaseApi) ForceStop(c echo.Context) error { + // 此处不再判断是否为安卓,直接控制若是安卓再注册对应API即可 + defer b.cleanupAndExit() + // this is a dangerous api, so we need to check the key + haskey := false + for _, s := range os.Environ() { + if strings.HasPrefix(s, "FSTOP_KEY=") { + key := strings.Split(s, "=")[1] + v := fStopEcho{} + err := c.Bind(&v) + if err != nil { + return response.FailWithMessage(response.GetGenericErrorMsg(err), c) + } + if v.Key == key { + haskey = true + break + } else { + return response.FailWithMessage("检查到FSTOP_KEY不对应,停止执行", c) + } + } + } + if !haskey { + return response.FailWithMessage("检查到环境中不含有FSTOP_KEY,停止执行", c) + } + return response.OkWithMessage("执行成功", c) +} + +// HeartBeat +// @Tags Base +// @Summary 心跳检测 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Success 200 {object} response.Result{msg=string} "返回心跳检测信息" +// @Router /base/heartbeat [get] +func (b *BaseApi) HeartBeat(c echo.Context) error { + // 需要鉴权 + return response.OkWithMessage("HEARTBEATS", c) +} + +// CheckSecurity +// @Tags Base +// @Summary 检查是否需要进行安全提醒 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Success 200 {object} response.Result{data=map[string]bool,msg=string} "返回安全检查结果" +// @Router /base/security/check [get] +func (b *BaseApi) CheckSecurity(c echo.Context) error { + // 需要鉴权 + isPublicService := strings.HasPrefix(b.dice.Parent.ServeAddress, "0.0.0.0") || b.dice.Parent.ServeAddress == ":3211" + isEmptyPassword := b.dice.Parent.UIPasswordHash == "" + return response.OkWithData(map[string]bool{ + "isOk": !(isEmptyPassword && isPublicService), + }, c) +} + +// 工具函数 +// cleanupAndExit 清理资源并退出程序 +func (b *BaseApi) cleanupAndExit() { + logger := b.dice.Logger + logger.Info("程序即将退出,进行清理……") + + defer func() { + if err := recover(); err != nil { + logger.Errorf("异常: %v\n堆栈: %v", err, string(debug.Stack())) + } + }() + // TODO:已经是单例模式了,这里其实不需要这么套娃 + for _, i := range b.dice.Parent.Dice { + if i.IsAlreadyLoadConfig { + i.Config.BanList.SaveChanged(i) + i.AttrsManager.CheckForSave() + i.Save(true) + + // 关闭存储 + for _, j := range i.ExtList { + if j.Storage != nil { + if err := j.StorageClose(); err != nil { + logger.Errorf("异常: %v\n堆栈: %v", err, string(debug.Stack())) + } + } + } + i.IsAlreadyLoadConfig = false + } + + b.closeDBConnections() + } + + // 清理gocqhttp + for _, i := range b.dice.Parent.Dice { + if i.ImSession != nil && i.ImSession.EndPoints != nil { + for _, j := range i.ImSession.EndPoints { + dice.BuiltinQQServeProcessKill(i, j) + } + } + } + + if b.dice.Parent.Help != nil { + b.dice.Parent.Help.Close() + } + if b.dice.Parent.IsReady { + b.dice.Parent.Save() + } + if b.dice.Parent.Cron != nil { + b.dice.Parent.Cron.Stop() + } + logger.Info("清理完成,程序即将退出") + os.Exit(0) //nolint:gocritic +} + +// closeDBConnections 关闭数据库连接 +func (b *BaseApi) closeDBConnections() { + diceInstance := b.dice + closeConnection := func(db *sqlx.DB) { + if db != nil { + _ = db.Close() + } + } + + closeConnection(diceInstance.DBData) + closeConnection(diceInstance.DBLogs) + + if cm := diceInstance.CensorManager; cm != nil { + closeConnection(cm.DB) + } +} + +func (b *BaseApi) getName() string { + defer func() { + // 防止报错 + _ = recover() + }() + + ctx := &dice.MsgContext{Dice: b.dice, EndPoint: nil, Session: b.dice.ImSession} + return dice.DiceFormatTmpl(ctx, "核心:骰子名字") +} diff --git a/api/v2/ui/enter.go b/api/v2/ui/enter.go new file mode 100644 index 00000000..2332a3b0 --- /dev/null +++ b/api/v2/ui/enter.go @@ -0,0 +1,17 @@ +package ui + +import ( + "sealdice-core/dice" +) + +// 管理所有WEBUI +type WebUIDiceGroup struct { + BaseApi *BaseApi + LoginApi *LoginApi +} + +func (a *WebUIDiceGroup) Init(d *dice.Dice) { + // 初始化API DICE引用,如果不是操作DICE的,到时候我们再单独开一栏,不传dice进去 + a.BaseApi = &BaseApi{dice: d} + a.LoginApi = &LoginApi{dice: d} +} diff --git a/api/v2/ui/login.go b/api/v2/ui/login.go new file mode 100644 index 00000000..13a7ed89 --- /dev/null +++ b/api/v2/ui/login.go @@ -0,0 +1,77 @@ +package ui + +import ( + "encoding/binary" + "encoding/hex" + "time" + + "github.com/labstack/echo/v4" + + "sealdice-core/dice" + "sealdice-core/utils/web/response" +) + +// LoginApi 存放登录接口,事实上这个本来想和base合并,但这样的话前端就会有一些要调整记录的工作量 +// 想法是等对接完毕并废弃V1接口后,再考虑合并。 +type LoginApi struct { + dice *dice.Dice +} + +// DoSignIn +// @Tags Base +// @Summary 用户登录 +// @Accept application/json +// @Produce application/json +// @Param password body string true "用户密码" +// @Success 200 {object} response.Result{data=map[string]string,msg=string} "返回登录成功的token" +// @Failure 400 {object} response.Result{msg=string} "返回参数绑定错误或登录失败信息" +// @Router /login/signin [post] +func (b *LoginApi) DoSignIn(c echo.Context) error { + v := struct { + Password string `json:"password"` + }{} + + err := c.Bind(&v) + if err != nil { + return response.FailWithMessage("参数绑定错误", c) + } + + // 如果UIPasswordHash为空,证明没有密码,自己生成一个 + if b.dice.Parent.UIPasswordHash == "" { + return response.OkWithData(map[string]string{ + "token": b.generateToken(), + }, c) + } + // 如果UIPasswordHash不为空,证明有密码,验证密码是否正确 + if b.dice.Parent.UIPasswordHash == v.Password { + return response.OkWithData(map[string]string{ + "token": b.generateToken(), + }, c) + } + return response.FailWithMessage("登录失败,请检查密码是否正确", c) +} + +// DoSignInGetSalt +// @Tags Base +// @Summary 获取密码盐 +// @Security ApiKeyAuth +// @Accept application/json +// @Produce application/json +// @Success 200 {object} response.Result{data=map[string]string,msg=string} "返回密码盐" +// @Router /login/salt [get] +func (b *LoginApi) DoSignInGetSalt(c echo.Context) error { + return response.OkWithData(map[string]string{ + "salt": b.dice.Parent.UIPasswordSalt, + }, c) +} + +// 工具函数放在最下面 +func (b *LoginApi) generateToken() string { + now := time.Now().Unix() + head := hex.EncodeToString(binary.BigEndian.AppendUint64(nil, uint64(now))) + token := dice.RandStringBytesMaskImprSrcSB2(64) + ":" + head + b.dice.Parent.AccessTokens[token] = true + b.dice.LastUpdatedTime = time.Now().Unix() + b.dice.Parent.Save() + return token +} diff --git a/main.go b/main.go index 974d15c1..fa3e574f 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,7 @@ import ( "go.uber.org/zap/zapcore" "sealdice-core/api" + v2 "sealdice-core/api/v2" "sealdice-core/dice" "sealdice-core/dice/model" "sealdice-core/migrate" @@ -615,6 +616,9 @@ func uiServe(dm *dice.DiceManager, hideUI bool, useBuiltin bool) { } api.Bind(e, dm) + // V2 ADD + v2.InitRouter(e, dm.Dice[0]) + e.HideBanner = true // 关闭banner,原因是banner图案会改变终端光标位置 httpServe(e, dm, hideUI) diff --git a/utils/kratos/const.go b/utils/kratos/const.go index 245435fc..bd1df850 100644 --- a/utils/kratos/const.go +++ b/utils/kratos/const.go @@ -4,6 +4,7 @@ const ( LOG_SEAL = "SEAL" LOG_DICE = "DICE" LOG_WEB = "WEB" + LOG_API = "API" LOG_LAGR = "LAGR" LOG_HIDE = "HIDE" ) diff --git a/utils/web/middleware/checkauth.go b/utils/web/middleware/checkauth.go deleted file mode 100644 index c870d7c1..00000000 --- a/utils/web/middleware/checkauth.go +++ /dev/null @@ -1 +0,0 @@ -package middleware diff --git a/utils/web/response/response.go b/utils/web/response/response.go index 5c8212be..83f0ee8e 100644 --- a/utils/web/response/response.go +++ b/utils/web/response/response.go @@ -15,7 +15,7 @@ type Response struct { Msg string `json:"msg"` } -var logger = log.NewCustomHelper(log.LOG_API, false, nil) +// 这里本来是初始化了一个自定义logger,但是好像会空指针,所以暂时用全局变量替代。 const ( ERROR = 400 @@ -24,7 +24,7 @@ const ( ) func GetGenericErrorMsg(err error) string { - return fmt.Sprintf("执行失败,原因为:%v ,请反馈开发者", err) + return fmt.Sprintf("执行失败,原因为:%v ,请反馈开发者", err.Error()) } func Result(code int, data interface{}, msg string, c echo.Context) error { @@ -35,20 +35,20 @@ func Result(code int, data interface{}, msg string, c echo.Context) error { Msg: msg, }) if err != nil { - logger.Debug("Error: ", err) + log.Debug("Error: ", err) return err } return nil } -func NoAuth(message string, c echo.Context) error { +func NoAuth(c echo.Context) error { err := c.JSON(http.StatusUnauthorized, Response{ - Code: 7, + Code: http.StatusUnauthorized, Data: nil, - Msg: message, + Msg: "您未登录或登录态已失效", }) if err != nil { - logger.Debug("Error: ", err) + log.Debug("Error: ", err) return err } return nil @@ -77,8 +77,3 @@ func Fail(c echo.Context) error { func FailWithMessage(message string, c echo.Context) error { return Result(ERROR, map[string]interface{}{}, message, c) } - -// 必要性不强,大部分情况下,我们不需要返回所谓data,只需要展示给用户提示信息即可 -// func FailWithDetailed(data interface{}, message string, c echo.Context) { -// Result(ERROR, data, message, c) -// }