diff --git a/internal/app/app.go b/internal/app/app.go new file mode 100644 index 00000000..c38b473f --- /dev/null +++ b/internal/app/app.go @@ -0,0 +1,39 @@ +package app + +import ( + "net/http" + + "github.com/gin-contrib/cors" + "github.com/gin-gonic/gin" +) + +func NewWebEngine() *gin.Engine { + e := gin.New() + e.HandleMethodNotAllowed = true + e.Use(gin.Logger()) + e.Use(gin.Recovery()) + + // 跨域配置 + corsConfig := cors.DefaultConfig() + corsConfig.AllowAllOrigins = true + corsConfig.AddAllowHeaders("Authorization") + e.Use(cors.New(corsConfig)) + + // 默认404 + e.NoRoute(func(c *gin.Context) { + c.JSON(http.StatusNotFound, gin.H{ + "code": 404, + "msg": "Not Found", + }) + }) + + // 默认405 + e.NoMethod(func(c *gin.Context) { + c.JSON(http.StatusMethodNotAllowed, gin.H{ + "code": 405, + "msg": "Method Not Allowed", + }) + }) + + return e +} diff --git a/internal/servants/core/xerror/common.go b/internal/servants/core/xerror/common.go new file mode 100644 index 00000000..a59c62e8 --- /dev/null +++ b/internal/servants/core/xerror/common.go @@ -0,0 +1,26 @@ +package xerror + +var ( + Success = NewError(0, "成功") + ServerError = NewError(10000, "服务内部错误") + InvalidParams = NewError(10001, "入参错误") + NotFound = NewError(10002, "找不到") + UnauthorizedAuthNotExist = NewError(10003, "账户不存在") + UnauthorizedAuthFailed = NewError(10004, "账户密码错误") + UnauthorizedTokenError = NewError(10005, "鉴权失败,Token 错误或丢失") + UnauthorizedTokenTimeout = NewError(10006, "鉴权失败,Token 超时") + UnauthorizedTokenGenerate = NewError(10007, "鉴权失败,Token 生成失败") + TooManyRequests = NewError(10008, "请求过多") + + GatewayMethodsLimit = NewError(10109, "网关仅接受GET或POST请求") + GatewayLostSign = NewError(10110, "网关请求缺少签名") + GatewayLostAppKey = NewError(10111, "网关请求缺少APP KEY") + GatewayAppKeyInvalid = NewError(10112, "网关请求无效APP KEY") + GatewayAppKeyClosed = NewError(10113, "网关请求APP KEY已停用") + GatewayParamSignError = NewError(10114, "网关请求参数签名错误") + GatewayTooManyRequests = NewError(10115, "网关请求频次超限") + + FileUploadFailed = NewError(10200, "文件上传失败") + FileInvalidExt = NewError(10201, "文件类型不合法") + FileInvalidSize = NewError(10202, "文件大小超限") +) diff --git a/internal/servants/core/xerror/xerror.go b/internal/servants/core/xerror/xerror.go new file mode 100644 index 00000000..b1b8a23a --- /dev/null +++ b/internal/servants/core/xerror/xerror.go @@ -0,0 +1,75 @@ +package xerror + +import ( + "fmt" + "net/http" +) + +type Error struct { + code int + msg string + details []string +} + +var codes = map[int]string{} + +func NewError(code int, msg string) *Error { + if _, ok := codes[code]; ok { + panic(fmt.Sprintf("错误码 %d 已经存在,请更换一个", code)) + } + codes[code] = msg + return &Error{code: code, msg: msg} +} + +func (e *Error) Error() string { + return fmt.Sprintf("错误码: %d, 错误信息: %s", e.Code(), e.Msg()) +} + +func (e *Error) Code() int { + return e.code +} + +func (e *Error) Msg() string { + return e.msg +} + +func (e *Error) Msgf(args []any) string { + return fmt.Sprintf(e.msg, args...) +} + +func (e *Error) Details() []string { + return e.details +} + +func (e *Error) WithDetails(details ...string) *Error { + newError := *e + newError.details = []string{} + newError.details = append(newError.details, details...) + + return &newError +} + +func (e *Error) StatusCode() int { + switch e.Code() { + case Success.Code(): + return http.StatusOK + case ServerError.Code(): + return http.StatusInternalServerError + case InvalidParams.Code(): + return http.StatusBadRequest + case UnauthorizedAuthNotExist.Code(): + fallthrough + case UnauthorizedAuthFailed.Code(): + fallthrough + case UnauthorizedTokenError.Code(): + fallthrough + case UnauthorizedTokenGenerate.Code(): + fallthrough + case UnauthorizedTokenTimeout.Code(): + return http.StatusUnauthorized + case TooManyRequests.Code(): + return http.StatusTooManyRequests + } + + return http.StatusInternalServerError +} diff --git a/internal/servants/docs.go b/internal/servants/docs.go new file mode 100644 index 00000000..9d53cac5 --- /dev/null +++ b/internal/servants/docs.go @@ -0,0 +1,13 @@ +//go:build !docs +// +build !docs + +package servants + +import ( + "github.com/gin-gonic/gin" +) + +// registerDocs stub function for register docs asset route +func registerDocs(e *gin.Engine) { + // empty +} diff --git a/internal/servants/docs_embed.go b/internal/servants/docs_embed.go new file mode 100644 index 00000000..aeb0b4cd --- /dev/null +++ b/internal/servants/docs_embed.go @@ -0,0 +1,17 @@ +//go:build docs +// +build docs + +package servants + +import ( + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/docs/openapi" + "github.com/rocboss/paopao-ce/internal/conf" +) + +// registerDocs register docs asset route +func registerDocs(e *gin.Engine) { + if conf.CfgIf("Docs:OpenAPI") { + e.StaticFS("/docs/openapi", openapi.NewFileSystem()) + } +} diff --git a/internal/servants/localoss.go b/internal/servants/localoss.go deleted file mode 100644 index b99a78f0..00000000 --- a/internal/servants/localoss.go +++ /dev/null @@ -1,5 +0,0 @@ -package servants - -type localossSrv struct { - // TODO -} diff --git a/internal/servants/localoss/localoss.go b/internal/servants/localoss/localoss.go new file mode 100644 index 00000000..ba37ddf8 --- /dev/null +++ b/internal/servants/localoss/localoss.go @@ -0,0 +1,28 @@ +package localoss + +import ( + "path/filepath" + + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/internal/conf" + "github.com/sirupsen/logrus" +) + +type localossSrv struct { + // TODO +} + +// RouteLocalOSS register LocalOSS route if needed +func RouteLocalOSS(e *gin.Engine) { + if !conf.CfgIf("LocalOSS") { + return + } + + savePath, err := filepath.Abs(conf.LocalOSSSetting.SavePath) + if err != nil { + logrus.Fatalf("get localOSS save path err: %v", err) + } + e.Static("/oss", savePath) + + logrus.Infof("register LocalOSS route in /oss on save path: %s", savePath) +} diff --git a/internal/servants/localoss/xerror.go b/internal/servants/localoss/xerror.go new file mode 100644 index 00000000..3014a991 --- /dev/null +++ b/internal/servants/localoss/xerror.go @@ -0,0 +1,11 @@ +package localoss + +import ( + "github.com/rocboss/paopao-ce/internal/servants/core/xerror" +) + +var ( + errFileUploadFailed = xerror.NewError(10200, "文件上传失败") + errFileInvalidExt = xerror.NewError(10201, "文件类型不合法") + errFileInvalidSize = xerror.NewError(10202, "文件大小超限") +) diff --git a/internal/servants/servants.go b/internal/servants/servants.go index 9cd595c7..fb03aff1 100644 --- a/internal/servants/servants.go +++ b/internal/servants/servants.go @@ -2,11 +2,18 @@ package servants import ( "github.com/gin-gonic/gin" - api "github.com/rocboss/paopao-ce/internal/mirc/auto/api/v1" + "github.com/rocboss/paopao-ce/internal/servants/localoss" "github.com/rocboss/paopao-ce/internal/servants/web" ) -// RegisterServants register all the servants to gin.Engine -func RegisterServants(e *gin.Engine) { - api.RegisterWebCoreServant(e, web.NewWebCoreSrv(), web.NewWebCoreBinding(), web.NewWebCoreRender()) +// RegisterWebServants register all the servants to gin.Engine +func RegisterWebServants(e *gin.Engine) { + // 按需注册 docs、静态资源 + { + registerDocs(e) + registerStatick(e) + } + + web.RouteWeb(e) + localoss.RouteLocalOSS(e) } diff --git a/internal/servants/statick.go b/internal/servants/statick.go new file mode 100644 index 00000000..d711dfe3 --- /dev/null +++ b/internal/servants/statick.go @@ -0,0 +1,13 @@ +//go:build !embed +// +build !embed + +package servants + +import ( + "github.com/gin-gonic/gin" +) + +// registerStatick stub function for register static asset route +func registerStatick(e *gin.Engine) { + // empty +} diff --git a/internal/servants/statick_embed.go b/internal/servants/statick_embed.go new file mode 100644 index 00000000..de212e55 --- /dev/null +++ b/internal/servants/statick_embed.go @@ -0,0 +1,27 @@ +//go:build embed +// +build embed + +package servants + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/rocboss/paopao-ce/web" +) + +// registerStatick register static assets route +func registerStatick(e *gin.Engine) { + routeStatic(e, "/", "/index.html", "/favicon.ico", "/assets/*filepath") +} + +func routeStatic(e *gin.Engine, paths ...string) { + staticHandler := http.FileServer(web.NewFileSystem()) + handler := func(c *gin.Context) { + staticHandler.ServeHTTP(c.Writer, c.Request) + } + for _, path := range paths { + e.GET(path, handler) + e.HEAD(path, handler) + } +} diff --git a/internal/servants/web/core.go b/internal/servants/web/core.go index 579b51b4..701e9fb2 100644 --- a/internal/servants/web/core.go +++ b/internal/servants/web/core.go @@ -25,3 +25,15 @@ type webCoreRender struct { core.BaseRender api.UnimplementedWebCoreRender } + +func newWebCoreSrv() api.WebCore { + return &webCoreSrv{} +} + +func newWebCoreBinding() api.WebCoreBinding { + return &webCoreBinding{} +} + +func newWebCoreRender() api.WebCoreRender { + return &webCoreRender{} +} diff --git a/internal/servants/web/web.go b/internal/servants/web/web.go index 5f505dc1..60a0aeb1 100644 --- a/internal/servants/web/web.go +++ b/internal/servants/web/web.go @@ -1,17 +1,11 @@ package web import ( + "github.com/gin-gonic/gin" api "github.com/rocboss/paopao-ce/internal/mirc/auto/api/v1" ) -func NewWebCoreSrv() api.WebCore { - return &webCoreSrv{} -} - -func NewWebCoreBinding() api.WebCoreBinding { - return &webCoreBinding{} -} - -func NewWebCoreRender() api.WebCoreRender { - return &webCoreRender{} +// RouteWeb register web route +func RouteWeb(e *gin.Engine) { + api.RegisterWebCoreServant(e, newWebCoreSrv(), newWebCoreBinding(), newWebCoreRender()) } diff --git a/internal/servants/web/xerror.go b/internal/servants/web/xerror.go new file mode 100644 index 00000000..0398f648 --- /dev/null +++ b/internal/servants/web/xerror.go @@ -0,0 +1,73 @@ +package web + +import ( + "github.com/rocboss/paopao-ce/internal/servants/core/xerror" +) + +var ( + errUsernameHasExisted = xerror.NewError(20001, "用户名已存在") + errUsernameLengthLimit = xerror.NewError(20002, "用户名长度3~12") + errUsernameCharLimit = xerror.NewError(20003, "用户名只能包含字母、数字") + errPasswordLengthLimit = xerror.NewError(20004, "密码长度6~16") + errUserRegisterFailed = xerror.NewError(20005, "用户注册失败") + errUserHasBeenBanned = xerror.NewError(20006, "该账户已被封停") + errNoPermission = xerror.NewError(20007, "无权限执行该请求") + errUserHasBindOTP = xerror.NewError(20008, "当前用户已绑定二次验证") + errUserOTPInvalid = xerror.NewError(20009, "二次验证码验证失败") + errUserNoBindOTP = xerror.NewError(20010, "当前用户未绑定二次验证") + errErrorOldPassword = xerror.NewError(20011, "当前用户密码验证失败") + errErrorCaptchaPassword = xerror.NewError(20012, "图形验证码验证失败") + errAccountNoPhoneBind = xerror.NewError(20013, "拒绝操作: 账户未绑定手机号") + errTooManyLoginError = xerror.NewError(20014, "登录失败次数过多,请稍后再试") + errGetPhoneCaptchaError = xerror.NewError(20015, "短信验证码获取失败") + errTooManyPhoneCaptchaSend = xerror.NewError(20016, "短信验证码获取次数已达今日上限") + errExistedUserPhone = xerror.NewError(20017, "该手机号已被绑定") + errErrorPhoneCaptcha = xerror.NewError(20018, "手机验证码不正确") + errMaxPhoneCaptchaUseTimes = xerror.NewError(20019, "手机验证码已达最大使用次数") + errNicknameLengthLimit = xerror.NewError(20020, "昵称长度2~12") + errNoExistUsername = xerror.NewError(20021, "用户不存在") + errNoAdminPermission = xerror.NewError(20022, "无管理权限") + + errGetPostsFailed = xerror.NewError(30001, "获取动态列表失败") + errCreatePostFailed = xerror.NewError(30002, "动态发布失败") + errGetPostFailed = xerror.NewError(30003, "获取动态详情失败") + errDeletePostFailed = xerror.NewError(30004, "动态删除失败") + errLockPostFailed = xerror.NewError(30005, "动态锁定失败") + errGetPostTagsFailed = xerror.NewError(30006, "获取话题列表失败") + errInvalidDownloadReq = xerror.NewError(30007, "附件下载请求不合法") + errDownloadReqError = xerror.NewError(30008, "附件下载请求失败") + errInsuffientDownloadMoney = xerror.NewError(30009, "附件下载失败:账户资金不足") + errDownloadExecFail = xerror.NewError(30010, "附件下载失败:扣费失败") + errStickPostFailed = xerror.NewError(30011, "动态置顶失败") + errVisblePostFailed = xerror.NewError(30012, "更新可见性失败") + + errGetCommentsFailed = xerror.NewError(40001, "获取评论列表失败") + errCreateCommentFailed = xerror.NewError(40002, "评论发布失败") + errGetCommentFailed = xerror.NewError(40003, "获取评论详情失败") + errDeleteCommentFailed = xerror.NewError(40004, "评论删除失败") + errCreateReplyFailed = xerror.NewError(40005, "评论回复失败") + errGetReplyFailed = xerror.NewError(40006, "获取评论详情失败") + errMaxCommentCount = xerror.NewError(40007, "评论数已达最大限制") + + errGetMessagesFailed = xerror.NewError(50001, "获取消息列表失败") + errReadMessageFailed = xerror.NewError(50002, "标记消息已读失败") + errSendWhisperFailed = xerror.NewError(50003, "私信发送失败") + errNoWhisperToSelf = xerror.NewError(50004, "不允许给自己发送私信") + errTooManyWhisperNum = xerror.NewError(50005, "今日私信次数已达上限") + + errGetCollectionsFailed = xerror.NewError(60001, "获取收藏列表失败") + errGetStarsFailed = xerror.NewError(60002, "获取点赞列表失败") + + errRechargeReqFail = xerror.NewError(70001, "充值请求失败") + errRechargeNotifyError = xerror.NewError(70002, "充值回调失败") + errGetRechargeFailed = xerror.NewError(70003, "充值详情获取失败") + + errNoRequestingFriendToSelf = xerror.NewError(80001, "不允许添加自己为好友") + errNotExistFriendId = xerror.NewError(80002, "好友id不存在") + errSendRequestingFriendFailed = xerror.NewError(80003, "申请添加朋友请求发送失败") + errAddFriendFailed = xerror.NewError(80004, "添加好友失败") + errRejectFriendFailed = xerror.NewError(80005, "拒绝好友失败") + errDeleteFriendFailed = xerror.NewError(80006, "删除好友失败") + errGetContactsFailed = xerror.NewError(80007, "获取联系人列表失败") + errNoActionToSelf = xerror.NewError(80008, "不允许对自己操作") +)