feat app 模块化启动
This commit is contained in:
11
Server/Gateway/Dockerfile
Normal file
11
Server/Gateway/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
||||
FROM alpine:latest
|
||||
|
||||
RUN apk add --no-cache tzdata && \
|
||||
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
|
||||
echo "Asia/Shanghai" > /etc/timezone
|
||||
|
||||
COPY gateway/ /app/
|
||||
RUN chmod 777 /app/server-gateway
|
||||
|
||||
WORKDIR /app
|
||||
CMD ["./server-gateway"]
|
||||
@@ -1,81 +1,60 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"common/db/etcd"
|
||||
"common/discover"
|
||||
"common/log"
|
||||
"common/net/grpc/service"
|
||||
"common/net/socket/websocket"
|
||||
"fmt"
|
||||
"gateway/config"
|
||||
"gateway/grpc_server/server"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/judwhite/go-svc"
|
||||
"runtime/debug"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Program struct {
|
||||
wg *sync.WaitGroup
|
||||
server service.IService // grpc服务
|
||||
webServer *gin.Engine // web服务
|
||||
wsServer *websocket.WSServer // websocket服务
|
||||
stop chan bool
|
||||
moduleList []Module // 模块列表
|
||||
}
|
||||
|
||||
type Module interface {
|
||||
Init() error
|
||||
Start() error
|
||||
Stop() error
|
||||
}
|
||||
|
||||
func (p *Program) Init(_ svc.Environment) error {
|
||||
if err := p.initBase(); err != nil {
|
||||
return err
|
||||
}
|
||||
cfg := config.Get()
|
||||
log.Infof(fmt.Sprintf("%v starting...", cfg.App.Name))
|
||||
if err := p.initDB(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.initWebServer(cfg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := p.initWsServer(cfg); err != nil {
|
||||
return err
|
||||
p.moduleList = append(p.moduleList, &ModuleBase{})
|
||||
p.moduleList = append(p.moduleList, &ModuleDB{})
|
||||
p.moduleList = append(p.moduleList, &ModuleWebServer{})
|
||||
p.moduleList = append(p.moduleList, &ModuleWebsocketServer{})
|
||||
p.moduleList = append(p.moduleList, &ModuleGrpcServer{})
|
||||
|
||||
for _, module := range p.moduleList {
|
||||
if err := module.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
log.Infof(fmt.Sprintf("%v Init successful...", config.Get().App.Name))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Program) Start() error {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Printf("Start err: %v", err)
|
||||
debug.PrintStack()
|
||||
_ = p.Stop()
|
||||
for _, module := range p.moduleList {
|
||||
if err := module.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
}()
|
||||
|
||||
}
|
||||
discover.Listen()
|
||||
p.server = server.NewServer(config.Get().Serve.Grpc.TTL)
|
||||
p.server.Init(config.Get().Serve.Grpc.Address, config.Get().Serve.Grpc.Port)
|
||||
go func() {
|
||||
cfg := config.Get()
|
||||
_ = p.wsServer.Run(
|
||||
log.GetLogger().Named("gnet"),
|
||||
fmt.Sprintf("tcp4://0.0.0.0:%v", cfg.Serve.Socket.Web.Port),
|
||||
true, true, false, false, true, 8,
|
||||
)
|
||||
}()
|
||||
|
||||
log.Infof(fmt.Sprintf("%v Start successful...", config.Get().App.Name))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Program) Stop() error {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
fmt.Printf("Stop err: %v", err)
|
||||
debug.PrintStack()
|
||||
}
|
||||
}()
|
||||
|
||||
discover.Close()
|
||||
p.server.Close()
|
||||
_ = etcd.Close()
|
||||
for i := len(p.moduleList) - 1; i >= 0; i-- {
|
||||
module := p.moduleList[i]
|
||||
if err := module.Stop(); err != nil {
|
||||
log.Errorf("module stop error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Infof(fmt.Sprintf("%v Stop successful...", config.Get().App.Name))
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -7,7 +7,11 @@ import (
|
||||
"math/rand"
|
||||
)
|
||||
|
||||
func (p *Program) initBase() error {
|
||||
// ModuleBase 基础模块,或者一些零散的模块
|
||||
type ModuleBase struct {
|
||||
}
|
||||
|
||||
func (p *ModuleBase) Init() error {
|
||||
// 配置
|
||||
if err := config.LoadConfig(); err != nil {
|
||||
return err
|
||||
@@ -17,6 +21,13 @@ func (p *Program) initBase() error {
|
||||
log.Init(cfg.Log.Debug, cfg.Log.MaxSize, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.Level)
|
||||
// 雪花
|
||||
utils.InitSnowflake(int64(rand.Intn(1000)))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ModuleBase) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ModuleBase) Stop() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,10 +2,16 @@ package app
|
||||
|
||||
import (
|
||||
"common/db/etcd"
|
||||
"common/log"
|
||||
"gateway/config"
|
||||
)
|
||||
|
||||
func (p *Program) initDB(cfg *config.Config) error {
|
||||
// ModuleDB 数据库模块
|
||||
type ModuleDB struct {
|
||||
}
|
||||
|
||||
func (p *ModuleDB) Init() error {
|
||||
cfg := config.Get()
|
||||
// ETCD
|
||||
if err := etcd.Init(cfg.DB.Etcd.Address); err != nil {
|
||||
return err
|
||||
@@ -13,8 +19,13 @@ func (p *Program) initDB(cfg *config.Config) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Program) stopDB() error {
|
||||
_ = etcd.Close()
|
||||
|
||||
func (p *ModuleDB) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *ModuleDB) Stop() error {
|
||||
if err := etcd.Close(); err != nil {
|
||||
log.Errorf("close etcd failed: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
27
Server/Gateway/app/grpc.go
Normal file
27
Server/Gateway/app/grpc.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"common/net/grpc/service"
|
||||
"gateway/config"
|
||||
"gateway/grpc_server/server"
|
||||
)
|
||||
|
||||
// ModuleGrpcServer Grpc服务模块
|
||||
type ModuleGrpcServer struct {
|
||||
server service.IService
|
||||
}
|
||||
|
||||
func (m *ModuleGrpcServer) Init() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ModuleGrpcServer) Start() error {
|
||||
m.server = server.NewServer(config.Get().Serve.Grpc.TTL)
|
||||
m.server.Init(config.Get().Serve.Grpc.Address, config.Get().Serve.Grpc.Port)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ModuleGrpcServer) Stop() error {
|
||||
m.server.Close()
|
||||
return nil
|
||||
}
|
||||
@@ -1,16 +1,49 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"common/log"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gateway/config"
|
||||
"gateway/net/http_gateway"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func (p *Program) initWebServer(cfg *config.Config) error {
|
||||
p.webServer = http_gateway.InitRouter(cfg)
|
||||
// ModuleWebServer Web服务模块
|
||||
type ModuleWebServer struct {
|
||||
wg *sync.WaitGroup
|
||||
server *http.Server
|
||||
router *gin.Engine
|
||||
}
|
||||
|
||||
func (m *ModuleWebServer) Init() error {
|
||||
m.wg = &sync.WaitGroup{}
|
||||
m.router = http_gateway.InitRouter(config.Get())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Program) stopWebServer() error {
|
||||
func (m *ModuleWebServer) Start() error {
|
||||
m.wg.Add(1)
|
||||
go func() {
|
||||
defer m.wg.Done()
|
||||
m.server = &http.Server{
|
||||
Addr: fmt.Sprintf("%v:%v", config.Get().Serve.Http.Address, config.Get().Serve.Http.Port),
|
||||
Handler: m.router,
|
||||
}
|
||||
if err := m.server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
log.Errorf("http server failed: %v", err.Error())
|
||||
}
|
||||
log.Infof("http server stop.")
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ModuleWebServer) Stop() error {
|
||||
if err := m.server.Close(); err != nil {
|
||||
log.Errorf("stop http server failed: %v", err)
|
||||
}
|
||||
m.wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,37 +3,51 @@ package app
|
||||
import (
|
||||
"common/log"
|
||||
"common/net/socket/websocket"
|
||||
"fmt"
|
||||
"gateway/config"
|
||||
"gateway/net/ws_gateway"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (p *Program) initWsServer(cfg *config.Config) error {
|
||||
//p.wsServer = websocket.NewWSServer(
|
||||
// &ws_gateway.GatewayWsServer{
|
||||
// Decoder: &ws_gateway.Decoder{},
|
||||
// },
|
||||
// log.GetLogger(),
|
||||
// fmt.Sprintf("tcp4://%v:%d", cfg.SocketServer.Host, cfg.SocketServer.Port),
|
||||
// true,
|
||||
// true,
|
||||
// false,
|
||||
// false,
|
||||
// true,
|
||||
// 8,
|
||||
// 5*time.Second,
|
||||
//)
|
||||
p.wsServer = websocket.NewWSServer(
|
||||
// ModuleWebsocketServer Websocket服务模块
|
||||
type ModuleWebsocketServer struct {
|
||||
wg *sync.WaitGroup
|
||||
server *websocket.WSServer
|
||||
}
|
||||
|
||||
func (m *ModuleWebsocketServer) Init() error {
|
||||
m.wg = &sync.WaitGroup{}
|
||||
m.server = websocket.NewWSServer(
|
||||
&ws_gateway.GatewayWsServer{},
|
||||
log.GetLogger().Named("ws_server"),
|
||||
5*time.Second,
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Program) stopWsServer() error {
|
||||
_ = p.wsServer.Stop()
|
||||
|
||||
func (m *ModuleWebsocketServer) Start() error {
|
||||
m.wg.Add(1)
|
||||
go func() {
|
||||
defer m.wg.Done()
|
||||
_ = m.server.Run(
|
||||
log.GetLogger().Named("GNET"),
|
||||
fmt.Sprintf("tcp4://0.0.0.0:%v", config.Get().Serve.Socket.Web.Port),
|
||||
true,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
8,
|
||||
)
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ModuleWebsocketServer) Stop() error {
|
||||
if err := m.server.Stop(); err != nil {
|
||||
log.Errorf("stop websocket server failed: %v", err)
|
||||
}
|
||||
m.wg.Wait()
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ app:
|
||||
log:
|
||||
debug: true
|
||||
level: "debug"
|
||||
maxSize: 100
|
||||
maxBackups: 3
|
||||
maxSize: 10
|
||||
maxBackups: 100
|
||||
maxAge: 7
|
||||
|
||||
db:
|
||||
@@ -19,11 +19,11 @@ serve:
|
||||
ttl: 20
|
||||
socket:
|
||||
web:
|
||||
address: "0.0.0.0"
|
||||
address: "127.0.0.1"
|
||||
port: 8501
|
||||
raw:
|
||||
address: "0.0.0.0"
|
||||
address: "127.0.0.1"
|
||||
port: 8502
|
||||
http:
|
||||
address: "0.0.0.0"
|
||||
address: "127.0.0.1"
|
||||
port: 8503
|
||||
|
||||
29
Server/Gateway/config/config.prod.yaml
Normal file
29
Server/Gateway/config/config.prod.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
app:
|
||||
name: "gateway-prod"
|
||||
|
||||
log:
|
||||
debug: false
|
||||
level: "debug"
|
||||
maxSize: 10
|
||||
maxBackups: 100
|
||||
maxAge: 7
|
||||
|
||||
db:
|
||||
etcd:
|
||||
address: [ "172.18.28.0:2379" ]
|
||||
|
||||
serve:
|
||||
grpc:
|
||||
address: "172.18.28.0"
|
||||
port: 8500
|
||||
ttl: 20
|
||||
socket:
|
||||
web:
|
||||
address: "172.18.28.0"
|
||||
port: 8501
|
||||
raw:
|
||||
address: "172.18.28.0"
|
||||
port: 8502
|
||||
http:
|
||||
address: "172.18.28.0"
|
||||
port: 8503
|
||||
18
Server/Gateway/handler/http_handler/helper/base.go
Normal file
18
Server/Gateway/handler/http_handler/helper/base.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package helper
|
||||
|
||||
type Pagination struct {
|
||||
Page int `json:"page"` // 页
|
||||
Size int `json:"size"` // 页大小
|
||||
}
|
||||
|
||||
//func SetBaseQuery(page *Pagination, order string) func(db *gorm.DB) *gorm.DB {
|
||||
// return func(db *gorm.DB) *gorm.DB {
|
||||
// if page != nil {
|
||||
// db = db.Offset((page.Page - 1) * page.Size).Limit(page.Size)
|
||||
// }
|
||||
// if len(order) > 0 {
|
||||
// db = db.Order(order)
|
||||
// }
|
||||
// return db
|
||||
// }
|
||||
//}
|
||||
31
Server/Gateway/handler/http_handler/helper/render/code.go
Normal file
31
Server/Gateway/handler/http_handler/helper/render/code.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package render
|
||||
|
||||
var (
|
||||
OK = NewCode(0, "成功")
|
||||
Failed = NewCode(1, "失败")
|
||||
ParamError = NewCode(1001, "参数错误")
|
||||
NameEmpty = NewCode(1002, "名称不能为空")
|
||||
NameDuplicate = NewCode(1003, "名称或编号不能重复")
|
||||
ListEmpty = NewCode(1004, "列表不能为空")
|
||||
RepeatCommit = NewCode(1005, "请勿重复提交")
|
||||
)
|
||||
|
||||
type Code struct {
|
||||
code int
|
||||
message string
|
||||
}
|
||||
|
||||
func NewCode(code int, message string) *Code {
|
||||
return &Code{
|
||||
code: code,
|
||||
message: message,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Code) Code() int {
|
||||
return c.code
|
||||
}
|
||||
|
||||
func (c *Code) Message() string {
|
||||
return c.message
|
||||
}
|
||||
30
Server/Gateway/handler/http_handler/helper/render/render.go
Normal file
30
Server/Gateway/handler/http_handler/helper/render/render.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package render
|
||||
|
||||
import (
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type RespJsonData struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data interface{} `json:"data"`
|
||||
}
|
||||
|
||||
func Json(c *gin.Context, code *Code, data interface{}) {
|
||||
result := &RespJsonData{
|
||||
Code: code.Code(),
|
||||
Msg: code.Message(),
|
||||
Data: data,
|
||||
}
|
||||
c.JSON(http.StatusOK, result)
|
||||
}
|
||||
|
||||
func AbortJson(c *gin.Context, code *Code, data interface{}) {
|
||||
result := &RespJsonData{
|
||||
Code: code.Code(),
|
||||
Msg: code.Message(),
|
||||
Data: data,
|
||||
}
|
||||
c.AbortWithStatusJSON(http.StatusOK, result)
|
||||
}
|
||||
16
Server/Gateway/handler/http_handler/unique_id.go
Normal file
16
Server/Gateway/handler/http_handler/unique_id.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package http_handler
|
||||
|
||||
import (
|
||||
"common/utils"
|
||||
"gateway/handler/http_handler/helper/render"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
type UniqueIDResp struct {
|
||||
ID string `json:"id"`
|
||||
}
|
||||
|
||||
// GenSnowflake 生成雪花ID
|
||||
func GenSnowflake(c *gin.Context) {
|
||||
render.Json(c, render.OK, &UniqueIDResp{ID: utils.SnowflakeInstance().Generate().String()})
|
||||
}
|
||||
37
Server/Gateway/net/http_gateway/middleward.go
Normal file
37
Server/Gateway/net/http_gateway/middleward.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package http_gateway
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
"time"
|
||||
)
|
||||
|
||||
func corsConfig() cors.Config {
|
||||
return cors.Config{
|
||||
AllowMethods: []string{"GET", "POST", "OPTIONS"},
|
||||
AllowHeaders: []string{"Content-Type", "Authorization"},
|
||||
AllowCredentials: false,
|
||||
AllowAllOrigins: true,
|
||||
MaxAge: 12 * time.Hour,
|
||||
}
|
||||
}
|
||||
|
||||
func ginLogger(logger *zap.SugaredLogger) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
start := time.Now()
|
||||
path := c.Request.URL.Path
|
||||
c.Next()
|
||||
cost := time.Since(start)
|
||||
|
||||
logger.Infof(fmt.Sprintf(
|
||||
"HTTP Method:%v Code:%v Time:%v IP:%v Path:%v",
|
||||
c.Request.Method,
|
||||
c.Writer.Status(),
|
||||
cost,
|
||||
c.ClientIP(),
|
||||
path),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,44 +1,43 @@
|
||||
package http_gateway
|
||||
|
||||
import (
|
||||
"common/log"
|
||||
"gateway/config"
|
||||
"gateway/handler/http_handler"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func InitRouter(cfg *config.Config) *gin.Engine {
|
||||
r := gin.Default()
|
||||
r.Use(gin.Recovery())
|
||||
r.Use(cors.New(getCorsConfig()))
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
r := gin.New()
|
||||
r.Use(
|
||||
gin.Recovery(),
|
||||
ginLogger(log.GetLogger().Named("GIN")),
|
||||
cors.New(corsConfig()),
|
||||
)
|
||||
|
||||
r.MaxMultipartMemory = 8 << 20
|
||||
r.HandleMethodNotAllowed = true
|
||||
r.NoMethod(func(c *gin.Context) {
|
||||
c.JSON(http.StatusMethodNotAllowed, gin.H{
|
||||
"result": false,
|
||||
"error": "Method Not Allowed",
|
||||
})
|
||||
return
|
||||
})
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.JSON(http.StatusNotFound, gin.H{
|
||||
"result": false,
|
||||
"error": "Endpoint Not Found",
|
||||
})
|
||||
return
|
||||
})
|
||||
initBaseRouter(r)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func getCorsConfig() cors.Config {
|
||||
return cors.Config{
|
||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
|
||||
AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization", "X-Forwarded-For", "User-Agent", "Referer", "X-Token", "token", "Token", "company-id", "lang", "source"},
|
||||
AllowCredentials: false,
|
||||
AllowAllOrigins: true,
|
||||
MaxAge: 12 * time.Hour,
|
||||
}
|
||||
func initBaseRouter(router *gin.Engine) {
|
||||
g := router.Group("/b")
|
||||
g.POST("/snowflake", http_handler.GenSnowflake) // 生成雪花
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user