feat: update

This commit is contained in:
ivamp 2024-06-16 00:55:25 +08:00
parent 8ea6ead6cc
commit a589e615e7
25 changed files with 187 additions and 164 deletions

View File

@ -1,4 +1,4 @@
package providers
package config
import (
"github.com/joho/godotenv"

View File

@ -1,7 +1,8 @@
package providers
package ent
import (
"errors"
"framework_v2/internal/app/logger"
_ "github.com/lib/pq"
"go.uber.org/zap"
)
@ -17,7 +18,7 @@ func InitEnt() {
err = errors.New("ent not implemented")
if err != nil {
Logger.Fatal("failed opening connection to db", zap.Error(err))
logger.Logger.Fatal("failed opening connection to db", zap.Error(err))
}
//
//if err := Ent.Schema.Create(

View File

@ -1,4 +1,4 @@
package access
package facades
import (
"github.com/gin-gonic/gin"

View File

@ -1,10 +1,11 @@
package providers
package gin
import (
"fmt"
"framework_v2/internal/access"
"framework_v2/internal/consts"
"framework_v2/internal/helper"
"framework_v2/internal/app/facades"
"framework_v2/internal/app/helpers"
"framework_v2/internal/app/user"
http2 "framework_v2/internal/middleware/http"
ginzap "github.com/gin-contrib/zap"
"github.com/gin-gonic/gin"
"net/http"
@ -15,9 +16,9 @@ import (
func InitGin() {
gin.SetMode(gin.ReleaseMode)
access.Router = gin.New()
facades.Router = gin.New()
access.Router.Use(ginzap.Ginzap(access.Logger, time.RFC3339, true))
facades.Router.Use(ginzap.Ginzap(facades.Logger, time.RFC3339, true))
//access.Router.Use(gin.Recovery())
//access.Router.Use(ginzap.RecoveryWithZap(access.Logger, true))
}
@ -44,31 +45,31 @@ func InitGin() {
//}
func GET(relativePath string, handlers ...interface{}) {
access.Router.GET(relativePath, func(c *gin.Context) {
facades.Router.GET(relativePath, func(c *gin.Context) {
doHandler(c, handlers...)
})
}
func POST(relativePath string, handlers ...interface{}) {
access.Router.POST(relativePath, func(c *gin.Context) {
facades.Router.POST(relativePath, func(c *gin.Context) {
doHandler(c, handlers...)
})
}
func PUT(relativePath string, handlers ...interface{}) {
access.Router.PUT(relativePath, func(c *gin.Context) {
facades.Router.PUT(relativePath, func(c *gin.Context) {
doHandler(c, handlers...)
})
}
func PATCH(relativePath string, handlers ...interface{}) {
access.Router.PATCH(relativePath, func(c *gin.Context) {
facades.Router.PATCH(relativePath, func(c *gin.Context) {
doHandler(c, handlers...)
})
}
func DELETE(relativePath string, handlers ...interface{}) {
access.Router.DELETE(relativePath, func(c *gin.Context) {
facades.Router.DELETE(relativePath, func(c *gin.Context) {
doHandler(c, handlers...)
})
}
@ -80,7 +81,7 @@ func doHandler(c *gin.Context, handlers ...interface{}) {
if c.Writer.Written() {
return
} else {
helper.ResponseError(c, http.StatusBadRequest, ErrEmptyResponse)
helpers.ResponseError(c, http.StatusBadRequest, http2.ErrEmptyResponse)
}
return
@ -103,15 +104,15 @@ func wrapHandler(c *gin.Context, f interface{}) {
switch argType {
case reflect.TypeOf((*gin.Context)(nil)):
argValue = reflect.ValueOf(c)
case reflect.TypeOf((*consts.User)(nil)):
userInfo := DIJWTAuth(c)
case reflect.TypeOf((*user.User)(nil)):
userInfo := http2.DIJWTAuth(c)
if userInfo == nil {
helper.ResponseError(c, http.StatusUnauthorized, ErrNotValidToken)
helpers.ResponseError(c, http.StatusUnauthorized, http2.ErrNotValidToken)
return
}
argValue = reflect.ValueOf(userInfo)
default:
helper.ResponseError(c, http.StatusBadRequest, fmt.Errorf("invalid argument type: %s", argType.String()))
helpers.ResponseError(c, http.StatusBadRequest, fmt.Errorf("invalid argument type: %s", argType.String()))
return
}

View File

@ -1,4 +1,4 @@
package helper
package helpers
func Offset(page int, pageSize int) int {
offset := (page - 1) * pageSize

View File

@ -1,12 +1,12 @@
package helper
package helpers
import (
"framework_v2/internal/consts"
"framework_v2/internal/app/response"
"github.com/gin-gonic/gin"
)
func ResponseMessage(c *gin.Context, code int, message string, data interface{}) {
c.JSON(code, &consts.BaseResponse{
c.JSON(code, &response.BaseResponse{
Message: message,
Code: code,
Data: data,
@ -15,7 +15,7 @@ func ResponseMessage(c *gin.Context, code int, message string, data interface{})
}
func Response(c *gin.Context, code int, data interface{}) {
c.JSON(code, &consts.BaseResponse{
c.JSON(code, &response.BaseResponse{
Code: code,
Data: data,
})
@ -23,7 +23,7 @@ func Response(c *gin.Context, code int, data interface{}) {
}
func ResponseError(c *gin.Context, code int, err error) {
c.JSON(code, &consts.BaseResponse{
c.JSON(code, &response.BaseResponse{
Error: err.Error(),
Code: code,
})

View File

@ -1,14 +1,17 @@
package providers
package jobs
import "github.com/hibiken/asynq"
import (
"framework_v2/internal/app/config"
"github.com/hibiken/asynq"
)
var AsynQClient *asynq.Client
var AsynQServer *asynq.Server
func getAsynQRedisOpt() asynq.RedisClientOpt {
return asynq.RedisClientOpt{
Addr: Config.Redis.Addr,
Password: Config.Redis.Pass,
Addr: config.Config.Redis.Addr,
Password: config.Config.Redis.Pass,
DB: 0,
}
}

View File

@ -1,9 +1,9 @@
package providers
package jwks
import (
"context"
"errors"
"framework_v2/internal/consts"
"framework_v2/internal/app/config"
"framework_v2/internal/app/logger"
"github.com/MicahParks/keyfunc/v3"
"github.com/golang-jwt/jwt/v5"
"time"
@ -28,16 +28,16 @@ func InitJwksRefresh() {
}
func RefreshJWKS() {
Logger.Info("Refreshing JWKS...")
logger.Logger.Info("Refreshing JWKS...")
var err error
Jwks, err = keyfunc.NewDefault([]string{Config.JWKS.Url})
Jwks, err = keyfunc.NewDefault([]string{config.Config.JWKS.Url})
if err != nil {
Logger.Error("Failed to create JWK Set from resource at the given URL.\nError: " + err.Error())
logger.Logger.Error("Failed to create JWK Set from resource at the given URL.\nError: " + err.Error())
}
Logger.Info("JWKS refreshed.")
logger.Logger.Info("JWKS refreshed.")
}
func ParseJWT(jwtB64 string) (*jwt.Token, error) {
@ -50,13 +50,3 @@ func ParseJWT(jwtB64 string) (*jwt.Token, error) {
return token, err
}
func GetAuthFromCtx(ctx context.Context) *consts.UserTokenInfo {
auth := ctx.Value(consts.UserTokenInfoKey)
if auth == nil {
return nil
}
return auth.(*consts.UserTokenInfo)
}

View File

@ -1,7 +1,7 @@
package providers
package logger
import (
"framework_v2/internal/access"
"framework_v2/internal/app/facades"
"go.uber.org/zap"
)
@ -19,5 +19,5 @@ func InitLogger() {
panic(err)
}
access.Logger = Logger
facades.Logger = Logger
}

View File

@ -1,8 +1,9 @@
package providers
package redis
import "C"
import (
"framework_v2/internal/access"
"framework_v2/internal/app/config"
"framework_v2/internal/app/facades"
"github.com/redis/go-redis/v9"
"golang.org/x/net/context"
)
@ -11,8 +12,8 @@ var Redis *redis.Client
func InitRedis() {
Redis = redis.NewClient(&redis.Options{
Addr: Config.Redis.Addr,
Password: Config.Redis.Pass,
Addr: config.Config.Redis.Addr,
Password: config.Config.Redis.Pass,
DB: 0, // use default DB
})
@ -24,5 +25,5 @@ func InitRedis() {
panic(err)
}
access.Redis = Redis
facades.Redis = Redis
}

View File

@ -1,4 +1,4 @@
package consts
package response
type BaseResponse struct {
Message string `json:"message"`

View File

@ -0,0 +1,14 @@
package server
import (
"framework_v2/internal/app/facades"
"framework_v2/internal/routes"
)
func InitHttp() {
if facades.Router == nil {
panic("You must call InitGin() before InitHttp()")
}
routes.InitApiRoutes()
}

View File

@ -1,4 +1,4 @@
package consts
package user
type UserTokenInfo struct {
Exp int `json:"exp"`

View File

@ -1,9 +1,13 @@
package cmd
import (
"framework_v2/internal/access"
internalHttp "framework_v2/internal/http"
"framework_v2/internal/providers"
"framework_v2/internal/app/config"
"framework_v2/internal/app/facades"
"framework_v2/internal/app/gin"
"framework_v2/internal/app/jobs"
"framework_v2/internal/app/jwks"
"framework_v2/internal/app/logger"
"framework_v2/internal/app/server"
"github.com/spf13/cobra"
)
@ -11,27 +15,27 @@ var httpCommand = &cobra.Command{
Use: "http",
Run: func(cmd *cobra.Command, args []string) {
providers.InitConfig()
providers.InitLogger()
config.InitConfig()
logger.InitLogger()
// you should uncommit it after run make ent
//providers.InitEnt()
//providers.InitRedis()
providers.InitJwksRefresh()
providers.InitAsynQClient()
providers.InitGin()
internalHttp.InitHttp()
jwks.InitJwksRefresh()
jobs.InitAsynQClient()
gin.InitGin()
server.InitHttp()
StartHttp()
},
}
func StartHttp() {
if providers.Config.HTTP.ListenAddr == "" {
providers.Config.HTTP.ListenAddr = "0.0.0.0:8080"
if config.Config.HTTP.ListenAddr == "" {
config.Config.HTTP.ListenAddr = "0.0.0.0:8080"
}
providers.Logger.Info("Http Server listening at " + providers.Config.HTTP.ListenAddr)
err := access.Router.Run(providers.Config.HTTP.ListenAddr)
logger.Logger.Info("Http Server listening at " + config.Config.HTTP.ListenAddr)
err := facades.Router.Run(config.Config.HTTP.ListenAddr)
if err != nil {
panic("failed to listen: " + err.Error())
}

View File

@ -7,9 +7,12 @@ import (
"entgo.io/ent/dialect/sql/schema"
"errors"
"fmt"
"framework_v2/internal/app/config"
"framework_v2/internal/app/ent"
"framework_v2/internal/app/logger"
//entmigrate "framework_v2/internal/ent/migrate"
"framework_v2/internal/migrations"
"framework_v2/internal/providers"
"github.com/golang-migrate/migrate/v4"
_ "github.com/golang-migrate/migrate/v4/database/postgres"
_ "github.com/golang-migrate/migrate/v4/source/file"
@ -26,9 +29,9 @@ var dsnCommand = &cobra.Command{
Short: "生成 DSN",
Long: "生成 DSN",
Run: func(cmd *cobra.Command, args []string) {
providers.InitConfig()
config.InitConfig()
fmt.Print(providers.Config.DB.Driver + "://" + providers.Config.DB.DSN)
fmt.Print(config.Config.DB.Driver + "://" + config.Config.DB.DSN)
},
}
@ -37,9 +40,9 @@ var migrateCommand = &cobra.Command{
Short: "迁移数据库",
Long: "适用于生产环境的数据库迁移",
Run: func(cmd *cobra.Command, args []string) {
providers.InitConfig()
providers.InitEnt()
providers.InitLogger()
config.InitConfig()
ent.InitEnt()
logger.InitLogger()
RunMigrate()
},
}
@ -49,9 +52,9 @@ var createMigrateCommand = &cobra.Command{
Short: "新建迁移",
Long: "从 internal/ent 中新建迁移。在这之前,需要运行 go generate ./internal/ent",
Run: func(cmd *cobra.Command, args []string) {
providers.InitConfig()
providers.InitEnt()
providers.InitLogger()
config.InitConfig()
ent.InitEnt()
logger.InitLogger()
generateMigration()
},
}
@ -60,7 +63,7 @@ var createMigrateCommand = &cobra.Command{
func RunMigrate() {
source, err := httpfs.New(http.FS(migrations.MigrationFS), ".")
mig, err := migrate.NewWithSourceInstance("httpfs", source, providers.Config.DB.Driver+"://"+providers.Config.DB.DSN)
mig, err := migrate.NewWithSourceInstance("httpfs", source, config.Config.DB.Driver+"://"+config.Config.DB.DSN)
if err != nil {
panic(err)

View File

@ -1,8 +1,13 @@
package cmd
import (
"framework_v2/internal/providers"
"framework_v2/internal/providers/interceptor"
"framework_v2/internal/app/config"
"framework_v2/internal/app/ent"
"framework_v2/internal/app/jobs"
"framework_v2/internal/app/jwks"
"framework_v2/internal/app/logger"
"framework_v2/internal/app/redis"
grpc2 "framework_v2/internal/middleware/grpc"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"github.com/spf13/cobra"
@ -16,36 +21,36 @@ var rpcCommand = &cobra.Command{
Use: "serve",
Run: func(cmd *cobra.Command, args []string) {
providers.InitConfig()
providers.InitLogger()
providers.InitEnt()
providers.InitRedis()
providers.InitJwksRefresh()
providers.InitAsynQClient()
config.InitConfig()
logger.InitLogger()
ent.InitEnt()
redis.InitRedis()
jwks.InitJwksRefresh()
jobs.InitAsynQClient()
StartSpiderService()
},
}
func StartSpiderService() {
if providers.Config.GRPC.GrpcListenAddr == "" {
providers.Config.GRPC.GrpcListenAddr = "0.0.0.0:8081"
if config.Config.GRPC.GrpcListenAddr == "" {
config.Config.GRPC.GrpcListenAddr = "0.0.0.0:8081"
}
lis, err := net.Listen("tcp", providers.Config.GRPC.GrpcListenAddr)
lis, err := net.Listen("tcp", config.Config.GRPC.GrpcListenAddr)
if err != nil {
panic("failed to listen: " + err.Error())
}
providers.Logger.Info("Server listening at " + providers.Config.GRPC.GrpcListenAddr)
logger.Logger.Info("Server listening at " + config.Config.GRPC.GrpcListenAddr)
var opts = []grpc.ServerOption{
grpc.ChainUnaryInterceptor(
logging.UnaryServerInterceptor(interceptor.ZapLogInterceptor()),
auth.UnaryServerInterceptor(interceptor.JwtAuth),
logging.UnaryServerInterceptor(grpc2.ZapLogInterceptor()),
auth.UnaryServerInterceptor(grpc2.JwtAuth),
),
grpc.ChainStreamInterceptor(
logging.StreamServerInterceptor(interceptor.ZapLogInterceptor()),
auth.StreamServerInterceptor(interceptor.JwtAuth),
logging.StreamServerInterceptor(grpc2.ZapLogInterceptor()),
auth.StreamServerInterceptor(grpc2.JwtAuth),
),
}
grpcServer := grpc.NewServer(opts...)

View File

@ -2,7 +2,11 @@ package cmd
import (
"fmt"
"framework_v2/internal/providers"
"framework_v2/internal/app/config"
"framework_v2/internal/app/ent"
"framework_v2/internal/app/jobs"
"framework_v2/internal/app/logger"
"framework_v2/internal/app/redis"
"github.com/spf13/cobra"
"time"
@ -12,11 +16,11 @@ var scheduleCommand = &cobra.Command{
Use: "schedule",
Run: func(cmd *cobra.Command, args []string) {
providers.InitConfig()
providers.InitLogger()
providers.InitEnt()
providers.InitRedis()
providers.InitAsynQClient()
config.InitConfig()
logger.InitLogger()
ent.InitEnt()
redis.InitRedis()
jobs.InitAsynQClient()
runSchedule()
},
@ -24,7 +28,7 @@ var scheduleCommand = &cobra.Command{
func runSchedule() {
if providers.Config.DebugMode.Enable {
if config.Config.DebugMode.Enable {
fmt.Println("调试模式开启,直接触发。")
// RUN JOB
return

View File

@ -1,7 +1,11 @@
package cmd
import (
"framework_v2/internal/providers"
"framework_v2/internal/app/config"
"framework_v2/internal/app/ent"
"framework_v2/internal/app/jobs"
"framework_v2/internal/app/logger"
"framework_v2/internal/app/redis"
"github.com/hibiken/asynq"
"github.com/spf13/cobra"
"log"
@ -11,11 +15,11 @@ var workerCommand = &cobra.Command{
Use: "worker",
Run: func(cmd *cobra.Command, args []string) {
providers.InitConfig()
providers.InitLogger()
providers.InitEnt()
providers.InitRedis()
providers.InitAsynQServer()
config.InitConfig()
logger.InitLogger()
ent.InitEnt()
redis.InitRedis()
jobs.InitAsynQServer()
runWorker()
},
@ -27,7 +31,7 @@ func runWorker() {
//mux.HandleFunc(tasks.DocumentChunkTask, tasks.HandleDocumentChunkTask)
//mux.HandleFunc(tasks.DocumentImportTask, tasks.HandleDocumentImportTask)
if err := providers.AsynQServer.Run(mux); err != nil {
if err := jobs.AsynQServer.Run(mux); err != nil {
log.Fatal(err)
}

View File

@ -2,7 +2,7 @@ package user
import (
"fmt"
"framework_v2/internal/consts"
"framework_v2/internal/app/user"
"github.com/gin-gonic/gin"
)
@ -13,7 +13,7 @@ import (
//
//}
func CurrentUser(c *gin.Context, user *consts.User) {
func CurrentUser(c *gin.Context, user *user.User) {
fmt.Println("CurrentUser", user)
c.JSON(200, gin.H{
"IP": c.ClientIP(),

View File

@ -1,14 +0,0 @@
package http
import (
"framework_v2/internal/access"
"framework_v2/internal/providers"
)
func InitHttp() {
if access.Router == nil {
panic("You must call InitGin() before InitHttp()")
}
providers.InitApiRoutes()
}

View File

@ -1,9 +1,11 @@
package interceptor
package grpc
import (
"context"
"framework_v2/internal/consts"
"framework_v2/internal/providers"
"framework_v2/internal/app/config"
"framework_v2/internal/app/jwks"
"framework_v2/internal/app/logger"
"framework_v2/internal/app/user"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/auth"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"github.com/mitchellh/mapstructure"
@ -18,14 +20,14 @@ func JwtAuth(ctx context.Context) (context.Context, error) {
}
sub := "anonymous"
var jwtIdToken *consts.UserTokenInfo
var jwtIdToken *user.UserTokenInfo
if providers.Config.DebugMode.Enable {
jwtIdToken = &consts.UserTokenInfo{
if config.Config.DebugMode.Enable {
jwtIdToken = &user.UserTokenInfo{
Sub: sub,
}
} else {
token, err := providers.ParseJWT(tokenString)
token, err := jwks.ParseJWT(tokenString)
if err != nil {
return nil, status.Errorf(codes.Unauthenticated, "invalid auth token: %v", err)
}
@ -36,7 +38,7 @@ func JwtAuth(ctx context.Context) (context.Context, error) {
err = mapstructure.Decode(token.Claims, &jwtIdToken)
if err != nil {
providers.Logger.Error("Failed to map token claims to JwtIDToken struct.\nError: " + err.Error())
logger.Logger.Error("Failed to map token claims to JwtIDToken struct.\nError: " + err.Error())
return nil, err
}
}

View File

@ -1,9 +1,9 @@
package interceptor
package grpc
import (
"context"
"fmt"
"framework_v2/internal/providers"
"framework_v2/internal/app/logger"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"go.uber.org/zap"
)
@ -28,17 +28,17 @@ func ZapLogInterceptor() logging.Logger {
}
}
logger := providers.Logger.WithOptions(zap.AddCallerSkip(1)).With(f...)
log := logger.Logger.WithOptions(zap.AddCallerSkip(1)).With(f...)
switch lvl {
case logging.LevelDebug:
logger.Debug(msg)
log.Debug(msg)
case logging.LevelInfo:
logger.Info(msg)
log.Info(msg)
case logging.LevelWarn:
logger.Warn(msg)
log.Warn(msg)
case logging.LevelError:
logger.Error(msg)
log.Error(msg)
default:
panic(fmt.Sprintf("unknown level %v", lvl))
}

View File

@ -1,9 +1,12 @@
package providers
package http
import (
"errors"
"framework_v2/internal/consts"
"framework_v2/internal/helper"
"framework_v2/internal/app/config"
"framework_v2/internal/app/facades"
"framework_v2/internal/app/helpers"
"framework_v2/internal/app/jwks"
"framework_v2/internal/app/user"
"github.com/gin-gonic/gin"
"github.com/mitchellh/mapstructure"
"net/http"
@ -20,47 +23,47 @@ var (
const AnonymousUser = "anonymous"
// DIJWTAuth 用于注入到方法签名中。我觉得下面的代码以后可以优化。
func DIJWTAuth(c *gin.Context) *consts.User {
func DIJWTAuth(c *gin.Context) *user.User {
var sub = AnonymousUser
var jwtIdToken = &consts.User{}
var jwtIdToken = &user.User{}
if Config.DebugMode.Enable {
if config.Config.DebugMode.Enable {
jwtIdToken.Token.Sub = sub
} else {
// get authorization header
authorization := c.Request.Header.Get("Authorization")
if authorization == "" {
helper.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
helpers.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
return nil
}
authSplit := strings.Split(authorization, " ")
if len(authSplit) != 2 {
helper.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
helpers.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
return nil
}
if authSplit[0] != "Bearer" {
helper.ResponseError(c, http.StatusUnauthorized, ErrNotBearerType)
helpers.ResponseError(c, http.StatusUnauthorized, ErrNotBearerType)
return nil
}
token, err := ParseJWT(authSplit[1])
token, err := jwks.ParseJWT(authSplit[1])
if err != nil {
helper.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
helpers.ResponseError(c, http.StatusUnauthorized, ErrJWTFormatError)
return nil
}
sub, err = token.Claims.GetSubject()
if err != nil {
helper.ResponseError(c, http.StatusUnauthorized, ErrNotValidToken)
helpers.ResponseError(c, http.StatusUnauthorized, ErrNotValidToken)
return nil
}
err = mapstructure.Decode(token.Claims, &jwtIdToken.Token)
if err != nil {
Logger.Error("Failed to map token claims to JwtIDToken struct.\nError: " + err.Error())
helper.ResponseError(c, http.StatusUnauthorized, ErrNotValidToken)
facades.Logger.Error("Failed to map token claims to JwtIDToken struct.\nError: " + err.Error())
helpers.ResponseError(c, http.StatusUnauthorized, ErrNotValidToken)
return nil
}
}

View File

@ -1,9 +0,0 @@
package providers
import (
"framework_v2/internal/http/controllers/user"
)
func InitApiRoutes() {
GET("/", MiddlewareJSONResponse, user.CurrentUser)
}

View File

@ -0,0 +1,11 @@
package routes
import (
"framework_v2/internal/app/gin"
"framework_v2/internal/http/controllers/user"
"framework_v2/internal/middleware/http"
)
func InitApiRoutes() {
gin.GET("/", http.MiddlewareJSONResponse, user.CurrentUser)
}