feat 结构调整
This commit is contained in:
@@ -22,7 +22,7 @@ func (p *Program) Init(_ svc.Environment) error {
|
||||
p.moduleList = append(p.moduleList, &ModuleBase{})
|
||||
p.moduleList = append(p.moduleList, &ModuleDB{})
|
||||
p.moduleList = append(p.moduleList, &ModulePrometheus{})
|
||||
p.moduleList = append(p.moduleList, &ModuleWebServer{})
|
||||
p.moduleList = append(p.moduleList, &ModuleGrpcGateway{})
|
||||
p.moduleList = append(p.moduleList, &ModuleWebsocketServer{})
|
||||
p.moduleList = append(p.moduleList, &ModuleGrpcServer{})
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ package app
|
||||
import (
|
||||
"common/net/grpc/service"
|
||||
"gateway/config"
|
||||
"gateway/grpc_server/server"
|
||||
"gateway/internal/grpc_server/server"
|
||||
)
|
||||
|
||||
// ModuleGrpcServer Grpc服务模块
|
||||
|
||||
63
Server/gateway/app/grpc_gateway.go
Normal file
63
Server/gateway/app/grpc_gateway.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"common/log"
|
||||
"common/net/grpc/service"
|
||||
"common/proto/ss/grpc_pb"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gateway/config"
|
||||
"gateway/internal/net/http_gateway"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// ModuleGrpcGateway GrpcGateway服务模块
|
||||
type ModuleGrpcGateway struct {
|
||||
wg *sync.WaitGroup
|
||||
// 微服务列表
|
||||
services []service.IService
|
||||
server *http.Server
|
||||
}
|
||||
|
||||
func (m *ModuleGrpcGateway) init() error {
|
||||
m.wg = &sync.WaitGroup{}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ModuleGrpcGateway) start() error {
|
||||
m.wg.Add(1)
|
||||
go func() {
|
||||
defer m.wg.Done()
|
||||
conn, err := service.UserNewClientLB()
|
||||
if err != nil {
|
||||
log.Errorf("get user conn failed: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
gwMux := http_gateway.InitServeMux()
|
||||
if err = grpc_pb.RegisterUserHandlerClient(context.Background(), gwMux, conn); err != nil {
|
||||
log.Errorf("RegisterUserHandlerClient err: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
m.server = &http.Server{
|
||||
Addr: fmt.Sprintf("%v:%v", config.Get().Serve.Http.Address, config.Get().Serve.Http.Port),
|
||||
Handler: http_gateway.InitRouter(gwMux),
|
||||
}
|
||||
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 *ModuleGrpcGateway) stop() error {
|
||||
if err := m.server.Shutdown(context.Background()); err != nil {
|
||||
log.Errorf("stop http server failed: %v", err)
|
||||
}
|
||||
m.wg.Wait()
|
||||
return nil
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"common/log"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"gateway/config"
|
||||
"gateway/net/http_gateway"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// 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()
|
||||
return nil
|
||||
}
|
||||
|
||||
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.Shutdown(context.Background()); err != nil {
|
||||
log.Errorf("stop http server failed: %v", err)
|
||||
}
|
||||
m.wg.Wait()
|
||||
return nil
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"common/net/socket/websocket"
|
||||
"fmt"
|
||||
"gateway/config"
|
||||
"gateway/net/ws_gateway"
|
||||
"gateway/internal/net/ws_gateway"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@@ -16,14 +16,6 @@ monitor:
|
||||
db:
|
||||
etcd:
|
||||
endpoints: [ "10.0.40.9:2379" ]
|
||||
mysql:
|
||||
user:
|
||||
dsn: "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/point?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
max_open_conn: 50
|
||||
max_idle_conn: 20
|
||||
conn_max_lifetime_sec: 600
|
||||
conn_max_idle_time_sec: 180
|
||||
log_level: "warn"
|
||||
|
||||
serve:
|
||||
grpc:
|
||||
|
||||
@@ -16,14 +16,6 @@ monitor:
|
||||
db:
|
||||
etcd:
|
||||
endpoints: [ "172.18.28.0:2379" ]
|
||||
mysql:
|
||||
user:
|
||||
dsn: "root:gR9pV4tY7zR6qL3e@tcp(47.108.184.184:3306)/point?charset=utf8mb4&parseTime=True&loc=Local"
|
||||
max_open_conn: 50
|
||||
max_idle_conn: 20
|
||||
conn_max_lifetime_sec: 600
|
||||
conn_max_idle_time_sec: 180
|
||||
log_level: "warn"
|
||||
|
||||
serve:
|
||||
grpc:
|
||||
|
||||
@@ -6,6 +6,7 @@ require (
|
||||
common v0.0.0-00010101000000-000000000000
|
||||
github.com/gin-contrib/cors v1.7.6
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
|
||||
github.com/judwhite/go-svc v1.2.1
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
go.uber.org/zap v1.27.0
|
||||
@@ -38,7 +39,6 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // 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
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
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
|
||||
// }
|
||||
//}
|
||||
@@ -1,31 +0,0 @@
|
||||
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
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
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 JsonByStatus(c *gin.Context, status int, code *Code, data interface{}) {
|
||||
result := &RespJsonData{
|
||||
Code: code.Code(),
|
||||
Msg: code.Message(),
|
||||
Data: data,
|
||||
}
|
||||
c.JSON(status, 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)
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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()})
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"common/log"
|
||||
"common/proto/sc/sc_pb"
|
||||
"common/proto/ss/grpc_pb"
|
||||
"gateway/handler/ws_handler"
|
||||
"gateway/internal/handler/ws_handler"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"sync"
|
||||
)
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"common/discover/common"
|
||||
"common/net/grpc/service"
|
||||
"common/proto/ss/grpc_pb"
|
||||
"gateway/handler/ws_handler"
|
||||
"gateway/internal/handler/ws_handler"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"common/net/grpc/service"
|
||||
"common/proto/sc/sc_pb"
|
||||
"common/proto/ss/grpc_pb"
|
||||
"gateway/grpc_server/stream_client"
|
||||
"gateway/internal/grpc_server/stream_client"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"time"
|
||||
)
|
||||
@@ -42,7 +42,7 @@ func (c *Client) handle(event Event) {
|
||||
}
|
||||
|
||||
func (c *Client) onEnter(msg *sc_pb.C2S_EnterInstance) {
|
||||
client, err := service.SceneNewClient()
|
||||
client, err := service.SceneNewClientLB()
|
||||
if err != nil {
|
||||
c.logger.Errorf("SceneNewClient err: %v", err)
|
||||
return
|
||||
54
Server/gateway/internal/net/http_gateway/router.go
Normal file
54
Server/gateway/internal/net/http_gateway/router.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package http_gateway
|
||||
|
||||
import (
|
||||
"common/log"
|
||||
"common/net/http/http_resp"
|
||||
wrapper2 "gateway/internal/net/http_gateway/wrapper"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func InitServeMux() *runtime.ServeMux {
|
||||
baseMarshaler := &runtime.JSONPb{
|
||||
MarshalOptions: protojson.MarshalOptions{
|
||||
UseProtoNames: false,
|
||||
EmitUnpopulated: true,
|
||||
},
|
||||
UnmarshalOptions: protojson.UnmarshalOptions{
|
||||
DiscardUnknown: true,
|
||||
},
|
||||
}
|
||||
unifiedMarshaler := wrapper2.NewWrappedMarshaler(baseMarshaler)
|
||||
|
||||
mux := runtime.NewServeMux(
|
||||
runtime.WithMarshalerOption(runtime.MIMEWildcard, unifiedMarshaler),
|
||||
runtime.WithErrorHandler(wrapper2.ErrorHandler),
|
||||
)
|
||||
return mux
|
||||
}
|
||||
|
||||
func InitRouter(mux *runtime.ServeMux) *gin.Engine {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
r := gin.New()
|
||||
r.Use(
|
||||
gin.Recovery(),
|
||||
ginLogger(log.GetLogger().Named("GIN")),
|
||||
cors.New(corsConfig()),
|
||||
)
|
||||
|
||||
r.HandleMethodNotAllowed = true
|
||||
r.NoMethod(func(c *gin.Context) {
|
||||
c.JSON(http.StatusMethodNotAllowed, http_resp.Error(http_resp.Failed.Code(), "Method Not Allowed"))
|
||||
})
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
c.JSON(http.StatusNotFound, http_resp.Error(http_resp.Failed.Code(), "Endpoint Not Found"))
|
||||
})
|
||||
|
||||
r.Any("/*any", gin.WrapH(mux))
|
||||
|
||||
return r
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"common/net/http/http_resp"
|
||||
"common/proto/ss/ss_common"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ErrorHandler 将 gRPC 错误转为统一 JSON 格式
|
||||
func ErrorHandler(_ context.Context, _ *runtime.ServeMux, _ runtime.Marshaler, w http.ResponseWriter, _ *http.Request, err error) {
|
||||
st, ok := status.FromError(err)
|
||||
if !ok {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
_ = json.NewEncoder(w).Encode(http_resp.Error(http_resp.Failed.Code(), http_resp.Failed.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
code, msg := 0, ""
|
||||
for _, detail := range st.Details() {
|
||||
if errorInfo, ok := detail.(*ss_common.ErrorInfo); ok {
|
||||
code = int(errorInfo.Code)
|
||||
msg = errorInfo.Msg
|
||||
break
|
||||
}
|
||||
}
|
||||
if code == 0 {
|
||||
code = http_resp.Failed.Code()
|
||||
msg = http_resp.Failed.Error()
|
||||
}
|
||||
if st.Code() == codes.Unknown {
|
||||
msg = st.Message()
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(grpcCodeToHTTPCode(st.Code()))
|
||||
_ = json.NewEncoder(w).Encode(http_resp.Error(code, msg))
|
||||
}
|
||||
|
||||
// 这里定义 Internal 属于业务错误,其他的属于 500 报错
|
||||
func grpcCodeToHTTPCode(c codes.Code) int {
|
||||
switch c {
|
||||
case codes.OK, codes.Unknown:
|
||||
return http.StatusOK
|
||||
default:
|
||||
return http.StatusInternalServerError
|
||||
}
|
||||
}
|
||||
42
Server/gateway/internal/net/http_gateway/wrapper/marshal.go
Normal file
42
Server/gateway/internal/net/http_gateway/wrapper/marshal.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package wrapper
|
||||
|
||||
import (
|
||||
"common/net/http/http_resp"
|
||||
"encoding/json"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"io"
|
||||
)
|
||||
|
||||
// WrappedMarshaler 自动包装响应为 { code, message, data }
|
||||
type WrappedMarshaler struct {
|
||||
inner runtime.Marshaler
|
||||
}
|
||||
|
||||
func NewWrappedMarshaler(inner runtime.Marshaler) *WrappedMarshaler {
|
||||
return &WrappedMarshaler{inner: inner}
|
||||
}
|
||||
|
||||
// Marshal 将 gRPC 响应包装成统一格式
|
||||
func (w *WrappedMarshaler) Marshal(v interface{}) ([]byte, error) {
|
||||
dataBytes, err := w.inner.Marshal(v)
|
||||
if err != nil {
|
||||
return json.Marshal(http_resp.Error(http_resp.Failed.Code(), http_resp.Failed.Error()))
|
||||
}
|
||||
return json.Marshal(http_resp.Success(json.RawMessage(dataBytes)))
|
||||
}
|
||||
|
||||
func (w *WrappedMarshaler) Unmarshal(data []byte, v interface{}) error {
|
||||
return w.inner.Unmarshal(data, v)
|
||||
}
|
||||
|
||||
func (w *WrappedMarshaler) NewDecoder(r io.Reader) runtime.Decoder {
|
||||
return w.inner.NewDecoder(r)
|
||||
}
|
||||
|
||||
func (w *WrappedMarshaler) NewEncoder(wr io.Writer) runtime.Encoder {
|
||||
return w.inner.NewEncoder(wr)
|
||||
}
|
||||
|
||||
func (w *WrappedMarshaler) ContentType(v interface{}) string {
|
||||
return "application/json"
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"common/log"
|
||||
"common/net/socket"
|
||||
"fmt"
|
||||
"gateway/handler/ws_handler"
|
||||
ws_handler2 "gateway/internal/handler/ws_handler"
|
||||
"go.uber.org/zap"
|
||||
"strconv"
|
||||
"time"
|
||||
@@ -30,29 +30,29 @@ func (g *GatewayWsServer) OnHandShake(conn socket.ISocketConn) {
|
||||
if err != nil {
|
||||
_ = conn.Close()
|
||||
}
|
||||
if oldClient := ws_handler.UserMgr.GetByUID(int32(t)); oldClient != nil {
|
||||
if oldClient := ws_handler2.UserMgr.GetByUID(int32(t)); oldClient != nil {
|
||||
oldClient.CloseClient()
|
||||
}
|
||||
client := ws_handler.NewClient(int32(t), conn)
|
||||
ws_handler.UserMgr.Add(int32(t), client)
|
||||
client := ws_handler2.NewClient(int32(t), conn)
|
||||
ws_handler2.UserMgr.Add(int32(t), client)
|
||||
conn.SetParam("client", client)
|
||||
}
|
||||
|
||||
func (g *GatewayWsServer) OnMessage(conn socket.ISocketConn, bytes []byte) socket.Action {
|
||||
client, ok := conn.GetParam("client").(*ws_handler.Client)
|
||||
client, ok := conn.GetParam("client").(*ws_handler2.Client)
|
||||
if !ok || client.UID == 0 {
|
||||
return socket.Close
|
||||
}
|
||||
client.OnEvent(&ws_handler.ClientEvent{Msg: bytes})
|
||||
client.OnEvent(&ws_handler2.ClientEvent{Msg: bytes})
|
||||
return socket.None
|
||||
}
|
||||
|
||||
func (g *GatewayWsServer) OnPong(conn socket.ISocketConn) {
|
||||
client, ok := conn.GetParam("client").(*ws_handler.Client)
|
||||
client, ok := conn.GetParam("client").(*ws_handler2.Client)
|
||||
if !ok || client.UID == 0 {
|
||||
return
|
||||
}
|
||||
client.OnEvent(&ws_handler.PongEvent{})
|
||||
client.OnEvent(&ws_handler2.PongEvent{})
|
||||
}
|
||||
|
||||
func (g *GatewayWsServer) OnClose(_ socket.ISocketConn, _ error) socket.Action {
|
||||
@@ -1,37 +0,0 @@
|
||||
package http_gateway
|
||||
|
||||
import (
|
||||
"common/log"
|
||||
"gateway/handler/http_handler"
|
||||
"gateway/handler/http_handler/helper/render"
|
||||
"github.com/gin-contrib/cors"
|
||||
"github.com/gin-gonic/gin"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func InitRouter() *gin.Engine {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
|
||||
r := gin.New()
|
||||
r.Use(
|
||||
gin.Recovery(),
|
||||
ginLogger(log.GetLogger().Named("GIN")),
|
||||
cors.New(corsConfig()),
|
||||
)
|
||||
|
||||
r.HandleMethodNotAllowed = true
|
||||
r.NoMethod(func(c *gin.Context) {
|
||||
render.JsonByStatus(c, http.StatusMethodNotAllowed, render.Failed, "Method Not Allowed")
|
||||
})
|
||||
r.NoRoute(func(c *gin.Context) {
|
||||
render.JsonByStatus(c, http.StatusNotFound, render.Failed, "Endpoint Not Found")
|
||||
})
|
||||
initBaseRouter(r)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func initBaseRouter(router *gin.Engine) {
|
||||
g := router.Group("/b")
|
||||
g.POST("/snowflake", http_handler.GenSnowflake) // 生成雪花
|
||||
}
|
||||
Reference in New Issue
Block a user