feat app 模块化启动
This commit is contained in:
@@ -10,7 +10,7 @@ class WebSocketService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
connect(squareId, onMessage, onStatusChange) {
|
connect(squareId, onMessage, onStatusChange) {
|
||||||
const wsUrl = `ws://localhost:8501/?token=${squareId}`;
|
const wsUrl = `wss://www.hlsq.asia/ws/?token=${squareId}`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ws = new WebSocket(wsUrl);
|
const ws = new WebSocket(wsUrl);
|
||||||
|
|||||||
6
Public/Publish/cmd.txt
Normal file
6
Public/Publish/cmd.txt
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
docker compose -p db -f docker-compose-db.yml up -d
|
||||||
|
docker compose -p tool -f docker-compose-tool.yml up -d
|
||||||
|
|
||||||
|
chown -R 1000:1000 jenkins/
|
||||||
|
|
||||||
|
ssh -L 2379:localhost:2379 root@47.108.184.184
|
||||||
31
Public/Publish/docker-compose-db.yml
Normal file
31
Public/Publish/docker-compose-db.yml
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mysql:latest
|
||||||
|
container_name: mysql
|
||||||
|
restart: always
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: gR9pV4tY7zR6qL3e
|
||||||
|
TZ: Asia/Shanghai
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
volumes:
|
||||||
|
- ./db/mysql:/var/lib/mysql
|
||||||
|
|
||||||
|
redis:
|
||||||
|
image: redis:latest
|
||||||
|
container_name: redis
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "6379:6379"
|
||||||
|
volumes:
|
||||||
|
- ./db/redis:/data
|
||||||
|
command: redis-server --requirepass lQ7aM8oB6lK0iD5k
|
||||||
|
|
||||||
|
etcd:
|
||||||
|
image: bitnami/etcd:latest
|
||||||
|
container_name: etcd
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- "2379:2379"
|
||||||
|
environment:
|
||||||
|
ALLOW_NONE_AUTHENTICATION: "yes"
|
||||||
26
Public/Publish/docker-compose-tool.yml
Normal file
26
Public/Publish/docker-compose-tool.yml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
services:
|
||||||
|
jenkins:
|
||||||
|
image: jenkins/jenkins:lts
|
||||||
|
container_name: jenkins
|
||||||
|
command: "--prefix=/jenkins"
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
volumes:
|
||||||
|
- ./jenkins:/var/jenkins_home
|
||||||
|
- /var/run/docker.sock:/var/run/docker.sock
|
||||||
|
- /usr/bin/docker:/usr/bin/docker
|
||||||
|
environment:
|
||||||
|
- TZ=Asia/Shanghai
|
||||||
|
|
||||||
|
nginx:
|
||||||
|
image: nginx:alpine
|
||||||
|
container_name: nginx
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "80:80"
|
||||||
|
- "443:443"
|
||||||
|
volumes:
|
||||||
|
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
||||||
|
- ./nginx/html:/var/www/html
|
||||||
|
- ./nginx/certs:/etc/nginx/certs:ro
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
version: '3.8'
|
|
||||||
services:
|
|
||||||
# ETCD 分布式键值存储
|
|
||||||
etcd:
|
|
||||||
image: quay.io/coreos/etcd:v3.5.4
|
|
||||||
container_name: etcd
|
|
||||||
ports:
|
|
||||||
- "2379:2379" # 客户端连接端口
|
|
||||||
- "2380:2380" # 节点通信端口
|
|
||||||
environment:
|
|
||||||
ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
|
|
||||||
ETCD_ADVERTISE_CLIENT_URLS: "http://etcd:2379"
|
|
||||||
ETCD_LISTEN_PEER_URLS: "http://0.0.0.0:2380"
|
|
||||||
ETCD_INITIAL_ADVERTISE_PEER_URLS: "http://etcd:2380"
|
|
||||||
ETCD_NAME: "etcd-single"
|
|
||||||
ETCD_INITIAL_CLUSTER: "etcd-single=http://etcd:2380"
|
|
||||||
ETCD_INITIAL_CLUSTER_TOKEN: "etcd-cluster"
|
|
||||||
ETCD_INITIAL_CLUSTER_STATE: "new"
|
|
||||||
volumes:
|
|
||||||
- etcd-data:/etcd-data
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
|
|
||||||
# Redis 缓存数据库
|
|
||||||
redis:
|
|
||||||
image: redis:7.0-alpine
|
|
||||||
container_name: redis
|
|
||||||
ports:
|
|
||||||
- "6379:6379"
|
|
||||||
volumes:
|
|
||||||
- redis-data:/data
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
command: redis-server --save 60 1 --loglevel warning
|
|
||||||
|
|
||||||
# MySQL 数据库
|
|
||||||
mysql:
|
|
||||||
image: mysql:8.0
|
|
||||||
container_name: mysql
|
|
||||||
environment:
|
|
||||||
MYSQL_ROOT_PASSWORD: rootpassword # 请更改为强密码
|
|
||||||
MYSQL_DATABASE: app_db
|
|
||||||
MYSQL_USER: app_user
|
|
||||||
MYSQL_PASSWORD: userpassword # 请更改为强密码
|
|
||||||
ports:
|
|
||||||
- "3306:3306"
|
|
||||||
volumes:
|
|
||||||
- mysql-data:/var/lib/mysql
|
|
||||||
- ./mysql-init:/docker-entrypoint-initdb.d # 初始化SQL脚本目录
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
|
||||||
interval: 5s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
# ETCD 可视化界面 (Web UI)
|
|
||||||
etcd-viewer:
|
|
||||||
image: deltaprojects/etcdkeeper:latest
|
|
||||||
container_name: etcd-viewer
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
environment:
|
|
||||||
ETCD_HOST: etcd
|
|
||||||
ETCD_PORT: 2379
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
depends_on:
|
|
||||||
- etcd
|
|
||||||
|
|
||||||
# 数据卷声明
|
|
||||||
volumes:
|
|
||||||
etcd-data:
|
|
||||||
redis-data:
|
|
||||||
mysql-data:
|
|
||||||
|
|
||||||
# 网络配置
|
|
||||||
networks:
|
|
||||||
app-network:
|
|
||||||
driver: bridge
|
|
||||||
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
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"common/db/etcd"
|
|
||||||
"common/discover"
|
"common/discover"
|
||||||
"common/log"
|
"common/log"
|
||||||
"common/net/grpc/service"
|
|
||||||
"common/net/socket/websocket"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"gateway/config"
|
"gateway/config"
|
||||||
"gateway/grpc_server/server"
|
|
||||||
"github.com/gin-gonic/gin"
|
|
||||||
"github.com/judwhite/go-svc"
|
"github.com/judwhite/go-svc"
|
||||||
"runtime/debug"
|
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Program struct {
|
type Program struct {
|
||||||
wg *sync.WaitGroup
|
moduleList []Module // 模块列表
|
||||||
server service.IService // grpc服务
|
}
|
||||||
webServer *gin.Engine // web服务
|
|
||||||
wsServer *websocket.WSServer // websocket服务
|
type Module interface {
|
||||||
stop chan bool
|
Init() error
|
||||||
|
Start() error
|
||||||
|
Stop() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) Init(_ svc.Environment) error {
|
func (p *Program) Init(_ svc.Environment) error {
|
||||||
if err := p.initBase(); err != nil {
|
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
|
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
|
|
||||||
}
|
}
|
||||||
|
log.Infof(fmt.Sprintf("%v Init successful...", config.Get().App.Name))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) Start() error {
|
func (p *Program) Start() error {
|
||||||
defer func() {
|
for _, module := range p.moduleList {
|
||||||
if err := recover(); err != nil {
|
if err := module.Start(); err != nil {
|
||||||
fmt.Printf("Start err: %v", err)
|
return err
|
||||||
debug.PrintStack()
|
}
|
||||||
_ = p.Stop()
|
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
|
||||||
discover.Listen()
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) Stop() error {
|
func (p *Program) Stop() error {
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
fmt.Printf("Stop err: %v", err)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
discover.Close()
|
discover.Close()
|
||||||
p.server.Close()
|
for i := len(p.moduleList) - 1; i >= 0; i-- {
|
||||||
_ = etcd.Close()
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ import (
|
|||||||
"math/rand"
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Program) initBase() error {
|
// ModuleBase 基础模块,或者一些零散的模块
|
||||||
|
type ModuleBase struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleBase) Init() error {
|
||||||
// 配置
|
// 配置
|
||||||
if err := config.LoadConfig(); err != nil {
|
if err := config.LoadConfig(); err != nil {
|
||||||
return err
|
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)
|
log.Init(cfg.Log.Debug, cfg.Log.MaxSize, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.Level)
|
||||||
// 雪花
|
// 雪花
|
||||||
utils.InitSnowflake(int64(rand.Intn(1000)))
|
utils.InitSnowflake(int64(rand.Intn(1000)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleBase) Start() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleBase) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"common/db/etcd"
|
"common/db/etcd"
|
||||||
|
"common/log"
|
||||||
"gateway/config"
|
"gateway/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Program) initDB(cfg *config.Config) error {
|
// ModuleDB 数据库模块
|
||||||
|
type ModuleDB struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleDB) Init() error {
|
||||||
|
cfg := config.Get()
|
||||||
// ETCD
|
// ETCD
|
||||||
if err := etcd.Init(cfg.DB.Etcd.Address); err != nil {
|
if err := etcd.Init(cfg.DB.Etcd.Address); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -13,8 +19,13 @@ func (p *Program) initDB(cfg *config.Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) stopDB() error {
|
func (p *ModuleDB) Start() error {
|
||||||
_ = etcd.Close()
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleDB) Stop() error {
|
||||||
|
if err := etcd.Close(); err != nil {
|
||||||
|
log.Errorf("close etcd failed: %v", err)
|
||||||
|
}
|
||||||
return nil
|
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
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"common/log"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"gateway/config"
|
"gateway/config"
|
||||||
"gateway/net/http_gateway"
|
"gateway/net/http_gateway"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Program) initWebServer(cfg *config.Config) error {
|
// ModuleWebServer Web服务模块
|
||||||
p.webServer = http_gateway.InitRouter(cfg)
|
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
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,37 +3,51 @@ package app
|
|||||||
import (
|
import (
|
||||||
"common/log"
|
"common/log"
|
||||||
"common/net/socket/websocket"
|
"common/net/socket/websocket"
|
||||||
|
"fmt"
|
||||||
"gateway/config"
|
"gateway/config"
|
||||||
"gateway/net/ws_gateway"
|
"gateway/net/ws_gateway"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Program) initWsServer(cfg *config.Config) error {
|
// ModuleWebsocketServer Websocket服务模块
|
||||||
//p.wsServer = websocket.NewWSServer(
|
type ModuleWebsocketServer struct {
|
||||||
// &ws_gateway.GatewayWsServer{
|
wg *sync.WaitGroup
|
||||||
// Decoder: &ws_gateway.Decoder{},
|
server *websocket.WSServer
|
||||||
// },
|
}
|
||||||
// log.GetLogger(),
|
|
||||||
// fmt.Sprintf("tcp4://%v:%d", cfg.SocketServer.Host, cfg.SocketServer.Port),
|
func (m *ModuleWebsocketServer) Init() error {
|
||||||
// true,
|
m.wg = &sync.WaitGroup{}
|
||||||
// true,
|
m.server = websocket.NewWSServer(
|
||||||
// false,
|
|
||||||
// false,
|
|
||||||
// true,
|
|
||||||
// 8,
|
|
||||||
// 5*time.Second,
|
|
||||||
//)
|
|
||||||
p.wsServer = websocket.NewWSServer(
|
|
||||||
&ws_gateway.GatewayWsServer{},
|
&ws_gateway.GatewayWsServer{},
|
||||||
log.GetLogger().Named("ws_server"),
|
log.GetLogger().Named("ws_server"),
|
||||||
5*time.Second,
|
5*time.Second,
|
||||||
)
|
)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) stopWsServer() error {
|
func (m *ModuleWebsocketServer) Start() error {
|
||||||
_ = p.wsServer.Stop()
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ app:
|
|||||||
log:
|
log:
|
||||||
debug: true
|
debug: true
|
||||||
level: "debug"
|
level: "debug"
|
||||||
maxSize: 100
|
maxSize: 10
|
||||||
maxBackups: 3
|
maxBackups: 100
|
||||||
maxAge: 7
|
maxAge: 7
|
||||||
|
|
||||||
db:
|
db:
|
||||||
@@ -19,11 +19,11 @@ serve:
|
|||||||
ttl: 20
|
ttl: 20
|
||||||
socket:
|
socket:
|
||||||
web:
|
web:
|
||||||
address: "0.0.0.0"
|
address: "127.0.0.1"
|
||||||
port: 8501
|
port: 8501
|
||||||
raw:
|
raw:
|
||||||
address: "0.0.0.0"
|
address: "127.0.0.1"
|
||||||
port: 8502
|
port: 8502
|
||||||
http:
|
http:
|
||||||
address: "0.0.0.0"
|
address: "127.0.0.1"
|
||||||
port: 8503
|
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
|
package http_gateway
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"common/log"
|
||||||
"gateway/config"
|
"gateway/config"
|
||||||
|
"gateway/handler/http_handler"
|
||||||
"github.com/gin-contrib/cors"
|
"github.com/gin-contrib/cors"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func InitRouter(cfg *config.Config) *gin.Engine {
|
func InitRouter(cfg *config.Config) *gin.Engine {
|
||||||
r := gin.Default()
|
gin.SetMode(gin.ReleaseMode)
|
||||||
r.Use(gin.Recovery())
|
|
||||||
r.Use(cors.New(getCorsConfig()))
|
r := gin.New()
|
||||||
|
r.Use(
|
||||||
|
gin.Recovery(),
|
||||||
|
ginLogger(log.GetLogger().Named("GIN")),
|
||||||
|
cors.New(corsConfig()),
|
||||||
|
)
|
||||||
|
|
||||||
r.MaxMultipartMemory = 8 << 20
|
|
||||||
r.HandleMethodNotAllowed = true
|
r.HandleMethodNotAllowed = true
|
||||||
r.NoMethod(func(c *gin.Context) {
|
r.NoMethod(func(c *gin.Context) {
|
||||||
c.JSON(http.StatusMethodNotAllowed, gin.H{
|
c.JSON(http.StatusMethodNotAllowed, gin.H{
|
||||||
"result": false,
|
"result": false,
|
||||||
"error": "Method Not Allowed",
|
"error": "Method Not Allowed",
|
||||||
})
|
})
|
||||||
return
|
|
||||||
})
|
})
|
||||||
r.NoRoute(func(c *gin.Context) {
|
r.NoRoute(func(c *gin.Context) {
|
||||||
c.JSON(http.StatusNotFound, gin.H{
|
c.JSON(http.StatusNotFound, gin.H{
|
||||||
"result": false,
|
"result": false,
|
||||||
"error": "Endpoint Not Found",
|
"error": "Endpoint Not Found",
|
||||||
})
|
})
|
||||||
return
|
|
||||||
})
|
})
|
||||||
|
initBaseRouter(r)
|
||||||
|
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
func getCorsConfig() cors.Config {
|
func initBaseRouter(router *gin.Engine) {
|
||||||
return cors.Config{
|
g := router.Group("/b")
|
||||||
AllowMethods: []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD"},
|
g.POST("/snowflake", http_handler.GenSnowflake) // 生成雪花
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
22
Server/build-all.bat
Normal file
22
Server/build-all.bat
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal
|
||||||
|
cd "%~dp0"
|
||||||
|
|
||||||
|
set GOOS=linux
|
||||||
|
set GOARCH=amd64
|
||||||
|
|
||||||
|
echo [INFO] Build started...
|
||||||
|
echo.
|
||||||
|
|
||||||
|
for %%p in (gateway scene) do (
|
||||||
|
echo [BUILD] server-%%p...
|
||||||
|
cd %%p
|
||||||
|
go build -o server-%%p
|
||||||
|
move server-%%p .. >nul
|
||||||
|
cd ..
|
||||||
|
)
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo [INFO] Build finished successfully!
|
||||||
|
|
||||||
|
endlocal
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -28,11 +29,14 @@ func LoadConfig[T any](configDir string, configPtr *T) (*T, error) {
|
|||||||
v.SetConfigType("yaml")
|
v.SetConfigType("yaml")
|
||||||
|
|
||||||
if err := v.ReadInConfig(); err != nil {
|
if err := v.ReadInConfig(); err != nil {
|
||||||
return nil, fmt.Errorf("读取配置失败: %w", err)
|
return nil, fmt.Errorf("failed to read config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := v.Unmarshal(&configPtr); err != nil {
|
if err := v.Unmarshal(&configPtr); err != nil {
|
||||||
return nil, fmt.Errorf("解析配置失败: %w", err)
|
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
marshal, _ := json.Marshal(configPtr)
|
||||||
|
fmt.Printf("Configuration loading completed: %v\n", string(marshal))
|
||||||
return configPtr, nil
|
return configPtr, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,77 @@
|
|||||||
package etcd
|
package etcd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"go.etcd.io/etcd/client/v3"
|
"go.etcd.io/etcd/client/v3"
|
||||||
|
"go.uber.org/zap"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
var cli *clientv3.Client
|
var instance *Client
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
cli *clientv3.Client
|
||||||
|
log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
// Init 初始化
|
||||||
func Init(endpoints []string) error {
|
func Init(endpoints []string) error {
|
||||||
client, err := clientv3.New(clientv3.Config{
|
client, err := clientv3.New(clientv3.Config{
|
||||||
Endpoints: endpoints,
|
Endpoints: endpoints,
|
||||||
DialTimeout: 5 * time.Second,
|
DialTimeout: 5 * time.Second,
|
||||||
})
|
})
|
||||||
cli = client
|
instance = &Client{
|
||||||
|
cli: client,
|
||||||
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func Client() *clientv3.Client {
|
// Close 关闭
|
||||||
return cli
|
|
||||||
}
|
|
||||||
|
|
||||||
func Close() error {
|
func Close() error {
|
||||||
if cli != nil {
|
if instance != nil && instance.cli != nil {
|
||||||
return cli.Close()
|
return instance.cli.Close()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetClient() *Client {
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get 获取数据
|
||||||
|
func (c *Client) Get(key string, opts ...clientv3.OpOption) (*clientv3.GetResponse, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
return c.cli.Get(ctx, key, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put 创建数据
|
||||||
|
func (c *Client) Put(key, val string, opts ...clientv3.OpOption) (*clientv3.PutResponse, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
return c.cli.Put(ctx, key, val, opts...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Grant 创建租约
|
||||||
|
func (c *Client) Grant(ttl int64) (*clientv3.LeaseGrantResponse, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
return c.cli.Grant(ctx, ttl)
|
||||||
|
}
|
||||||
|
|
||||||
|
// KeepAlive 保活租约
|
||||||
|
func (c *Client) KeepAlive(id clientv3.LeaseID) (<-chan *clientv3.LeaseKeepAliveResponse, error) {
|
||||||
|
return c.cli.KeepAlive(context.Background(), id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Revoke 撤销租约
|
||||||
|
func (c *Client) Revoke(id clientv3.LeaseID) (*clientv3.LeaseRevokeResponse, error) {
|
||||||
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
return c.cli.Revoke(ctx, id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watch 监听数据
|
||||||
|
func (c *Client) Watch(key string, opts ...clientv3.OpOption) clientv3.WatchChan {
|
||||||
|
return c.cli.Watch(context.Background(), key, opts...)
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,27 +3,23 @@ package common
|
|||||||
import (
|
import (
|
||||||
"common/db/etcd"
|
"common/db/etcd"
|
||||||
"common/log"
|
"common/log"
|
||||||
"context"
|
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewLeaseAndKeepAlive 创建租约并保活
|
// NewLeaseAndKeepAlive 创建租约并保活
|
||||||
func NewLeaseAndKeepAlive(ttl int64) (clientv3.LeaseID, error) {
|
func NewLeaseAndKeepAlive(ttl int64) (clientv3.LeaseID, error) {
|
||||||
lease, err := etcd.Client().Grant(context.Background(), ttl)
|
lease, err := etcd.GetClient().Grant(ttl)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
chKeepAlive, err := etcd.Client().KeepAlive(context.Background(), lease.ID)
|
chKeepAlive, err := etcd.GetClient().KeepAlive(lease.ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
go func() {
|
go func(leaseID clientv3.LeaseID) {
|
||||||
for r := range chKeepAlive {
|
for range chKeepAlive {
|
||||||
if r == nil {
|
|
||||||
log.Errorf("lease timeout!")
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
log.Warnf("Lease %x expired or revoked", leaseID)
|
||||||
}()
|
}(lease.ID)
|
||||||
return lease.ID, nil
|
return lease.ID, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"common/db/etcd"
|
"common/db/etcd"
|
||||||
"common/discover/common"
|
"common/discover/common"
|
||||||
"common/log"
|
"common/log"
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -42,7 +41,7 @@ func RegisterInstance(sid int64, instanceID int, uniqueNo, ttl int64) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
key := fmt.Sprintf("%v/%v/%v", common.KeyDiscoverInstance, instanceID, uniqueNo)
|
key := fmt.Sprintf("%v/%v/%v", common.KeyDiscoverInstance, instanceID, uniqueNo)
|
||||||
_, err = etcd.Client().Put(context.Background(), key, strconv.Itoa(int(sid)), clientv3.WithLease(leaseID))
|
_, err = etcd.GetClient().Put(key, strconv.Itoa(int(sid)), clientv3.WithLease(leaseID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -55,7 +54,7 @@ func UnRegisterInstance(uniqueNo int64) {
|
|||||||
serverMU.Lock()
|
serverMU.Lock()
|
||||||
defer serverMU.Unlock()
|
defer serverMU.Unlock()
|
||||||
if leaseID, ok := instanceLeaseM[uniqueNo]; ok {
|
if leaseID, ok := instanceLeaseM[uniqueNo]; ok {
|
||||||
_, err := etcd.Client().Revoke(context.Background(), leaseID)
|
_, err := etcd.GetClient().Revoke(leaseID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("UnRegisterInstance err: %v", err)
|
log.Errorf("UnRegisterInstance err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,10 @@ package discover
|
|||||||
import (
|
import (
|
||||||
"common/db/etcd"
|
"common/db/etcd"
|
||||||
"common/discover/common"
|
"common/discover/common"
|
||||||
|
"common/log"
|
||||||
"common/utils"
|
"common/utils"
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"go.etcd.io/etcd/api/v3/mvccpb"
|
"go.etcd.io/etcd/api/v3/mvccpb"
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -46,18 +48,19 @@ func Listen() {
|
|||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
|
log.Infof(fmt.Sprintf("Discover start listen..."))
|
||||||
// 服务
|
// 服务
|
||||||
serviceAll, _ := etcd.Client().Get(stopCtx, common.KeyDiscoverService, clientv3.WithPrefix())
|
serviceAll, _ := etcd.GetClient().Get(common.KeyDiscoverService, clientv3.WithPrefix())
|
||||||
for _, kv := range serviceAll.Kvs {
|
for _, kv := range serviceAll.Kvs {
|
||||||
onServerChange(clientv3.EventTypePut, string(kv.Key), string(kv.Value))
|
onServerChange(clientv3.EventTypePut, string(kv.Key), string(kv.Value))
|
||||||
}
|
}
|
||||||
chService := etcd.Client().Watch(stopCtx, common.KeyDiscoverService, clientv3.WithPrefix(), clientv3.WithRev(serviceAll.Header.Revision+1))
|
chService := etcd.GetClient().Watch(common.KeyDiscoverService, clientv3.WithPrefix(), clientv3.WithRev(serviceAll.Header.Revision+1))
|
||||||
// 副本
|
// 副本
|
||||||
instanceAll, _ := etcd.Client().Get(stopCtx, common.KeyDiscoverInstance, clientv3.WithPrefix())
|
instanceAll, _ := etcd.GetClient().Get(common.KeyDiscoverInstance, clientv3.WithPrefix())
|
||||||
for _, kv := range instanceAll.Kvs {
|
for _, kv := range instanceAll.Kvs {
|
||||||
onInstanceChange(clientv3.EventTypePut, string(kv.Key), string(kv.Value), nil)
|
onInstanceChange(clientv3.EventTypePut, string(kv.Key), string(kv.Value), nil)
|
||||||
}
|
}
|
||||||
chInstance := etcd.Client().Watch(stopCtx, common.KeyDiscoverScene, clientv3.WithPrefix(), clientv3.WithRev(instanceAll.Header.Revision+1), clientv3.WithPrevKV())
|
chInstance := etcd.GetClient().Watch(common.KeyDiscoverScene, clientv3.WithPrefix(), clientv3.WithRev(instanceAll.Header.Revision+1), clientv3.WithPrevKV())
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case msg := <-chService:
|
case msg := <-chService:
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"common/discover/common"
|
"common/discover/common"
|
||||||
"common/log"
|
"common/log"
|
||||||
"common/net/grpc/grpc_conn"
|
"common/net/grpc/grpc_conn"
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
@@ -51,7 +50,7 @@ func RegisterGrpcServer(target string, sid int64, addr string, ttl int64) error
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, err = etcd.Client().Put(context.Background(), fmt.Sprintf("%v/%v", target, sid), addr, clientv3.WithLease(leaseID))
|
_, err = etcd.GetClient().Put(fmt.Sprintf("%v/%v", target, sid), addr, clientv3.WithLease(leaseID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -64,7 +63,7 @@ func UnRegisterGrpcServer(sid int64) {
|
|||||||
serverMU.Lock()
|
serverMU.Lock()
|
||||||
defer serverMU.Unlock()
|
defer serverMU.Unlock()
|
||||||
if leaseID, ok := serverLeaseM[sid]; ok {
|
if leaseID, ok := serverLeaseM[sid]; ok {
|
||||||
_, err := etcd.Client().Revoke(context.Background(), leaseID)
|
_, err := etcd.GetClient().Revoke(leaseID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("server.go UnRegisterGrpcServer err: %v", err)
|
log.Errorf("server.go UnRegisterGrpcServer err: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
11
Server/publish/gateway/Dockerfile
Normal file
11
Server/publish/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"]
|
||||||
29
Server/publish/gateway/config/config.prod.yaml
Normal file
29
Server/publish/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
|
||||||
19
Server/publish/publish.bat
Normal file
19
Server/publish/publish.bat
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
@echo off
|
||||||
|
|
||||||
|
call ../build-all.bat
|
||||||
|
echo.
|
||||||
|
|
||||||
|
rd /s /q gateway
|
||||||
|
xcopy ..\gateway\config\config.prod.yaml gateway\config\ >nul
|
||||||
|
xcopy ..\gateway\Dockerfile gateway\ >nul
|
||||||
|
move ..\server-gateway gateway\ >nul
|
||||||
|
echo [INFO] Copy gateway finished.
|
||||||
|
|
||||||
|
rd /s /q scene
|
||||||
|
xcopy ..\scene\config\config.prod.yaml scene\config\ >nul
|
||||||
|
xcopy ..\scene\Dockerfile scene\ >nul
|
||||||
|
move ..\server-scene scene\ >nul
|
||||||
|
echo [INFO] Copy scene finished.
|
||||||
|
|
||||||
|
echo.
|
||||||
|
pause
|
||||||
7
Server/publish/run_gateway.sh
Normal file
7
Server/publish/run_gateway.sh
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker stop server-gateway
|
||||||
|
docker rm server-gateway
|
||||||
|
docker rmi server-gateway:latest
|
||||||
|
|
||||||
|
docker build -f ./gateway/Dockerfile . -t server-gateway
|
||||||
|
docker run -d --name server-gateway -p 8500-8503:8500-8503 --privileged=true --env XH_G_ENV=prod -v /root/server/logs/gateway_log/:/app/logs server-gateway
|
||||||
7
Server/publish/run_scene.sh
Normal file
7
Server/publish/run_scene.sh
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
docker stop server-scene
|
||||||
|
docker rm server-scene
|
||||||
|
docker rmi server-scene:latest
|
||||||
|
|
||||||
|
docker build -f ./scene/Dockerfile . -t server-scene
|
||||||
|
docker run -d --name server-scene -p 8504:8504 --privileged=true --env XH_G_ENV=prod -v /root/server/logs/scene_log/:/app/logs server-scene
|
||||||
11
Server/publish/scene/Dockerfile
Normal file
11
Server/publish/scene/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 scene/ /app/
|
||||||
|
RUN chmod 777 /app/server-scene
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
CMD ["./server-scene"]
|
||||||
19
Server/publish/scene/config/config.prod.yaml
Normal file
19
Server/publish/scene/config/config.prod.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
app:
|
||||||
|
name: "scene-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: 8504
|
||||||
|
ttl: 20
|
||||||
11
Server/scene/Dockerfile
Normal file
11
Server/scene/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 scene/ /app/
|
||||||
|
RUN chmod 777 /app/server-scene
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
CMD ["./server-scene"]
|
||||||
@@ -1,63 +1,58 @@
|
|||||||
package app
|
package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"common/db/etcd"
|
|
||||||
"common/discover"
|
"common/discover"
|
||||||
"common/log"
|
"common/log"
|
||||||
"common/net/grpc/service"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/judwhite/go-svc"
|
"github.com/judwhite/go-svc"
|
||||||
"runtime/debug"
|
|
||||||
"scene/config"
|
"scene/config"
|
||||||
"scene/grpc_server/server"
|
|
||||||
"sync"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Program struct {
|
type Program struct {
|
||||||
wg *sync.WaitGroup
|
moduleList []Module // 模块列表
|
||||||
server service.IService // grpc服务
|
}
|
||||||
stop chan bool
|
|
||||||
|
type Module interface {
|
||||||
|
Init() error
|
||||||
|
Start() error
|
||||||
|
Stop() error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) Init(_ svc.Environment) error {
|
func (p *Program) Init(_ svc.Environment) error {
|
||||||
if err := p.initBase(); err != nil {
|
p.moduleList = append(p.moduleList, &ModuleBase{})
|
||||||
|
p.moduleList = append(p.moduleList, &ModuleDB{})
|
||||||
|
p.moduleList = append(p.moduleList, &ModuleGrpcServer{})
|
||||||
|
|
||||||
|
for _, module := range p.moduleList {
|
||||||
|
if err := module.Init(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
cfg := config.Get()
|
|
||||||
log.Infof(fmt.Sprintf("%v starting...", cfg.App.Name))
|
|
||||||
if err := p.initDB(cfg); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
log.Infof(fmt.Sprintf("%v Init successful...", config.Get().App.Name))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) Start() error {
|
func (p *Program) Start() error {
|
||||||
defer func() {
|
for _, module := range p.moduleList {
|
||||||
if err := recover(); err != nil {
|
if err := module.Start(); err != nil {
|
||||||
fmt.Printf("Start err: %v", err)
|
return err
|
||||||
debug.PrintStack()
|
}
|
||||||
_ = p.Stop()
|
|
||||||
}
|
}
|
||||||
}()
|
|
||||||
|
|
||||||
discover.Listen()
|
discover.Listen()
|
||||||
p.server = server.NewServer(config.Get().Serve.Grpc.TTL)
|
|
||||||
p.server.Init(config.Get().Serve.Grpc.Address, config.Get().Serve.Grpc.Port)
|
|
||||||
|
|
||||||
|
log.Infof(fmt.Sprintf("%v Start successful...", config.Get().App.Name))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) Stop() error {
|
func (p *Program) Stop() error {
|
||||||
defer func() {
|
|
||||||
if err := recover(); err != nil {
|
|
||||||
fmt.Printf("Stop err: %v", err)
|
|
||||||
debug.PrintStack()
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
discover.Close()
|
discover.Close()
|
||||||
p.server.Close()
|
for i := len(p.moduleList) - 1; i >= 0; i-- {
|
||||||
_ = etcd.Close()
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,11 @@ import (
|
|||||||
"scene/config"
|
"scene/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Program) initBase() error {
|
// ModuleBase 基础模块,或者一些零散的模块
|
||||||
|
type ModuleBase struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleBase) Init() error {
|
||||||
// 配置
|
// 配置
|
||||||
if err := config.LoadConfig(); err != nil {
|
if err := config.LoadConfig(); err != nil {
|
||||||
return err
|
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)
|
log.Init(cfg.Log.Debug, cfg.Log.MaxSize, cfg.Log.MaxBackups, cfg.Log.MaxAge, cfg.Log.Level)
|
||||||
// 雪花
|
// 雪花
|
||||||
utils.InitSnowflake(int64(rand.Intn(1000)))
|
utils.InitSnowflake(int64(rand.Intn(1000)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleBase) Start() error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleBase) Stop() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,10 +2,16 @@ package app
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"common/db/etcd"
|
"common/db/etcd"
|
||||||
|
"common/log"
|
||||||
"scene/config"
|
"scene/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (p *Program) initDB(cfg *config.Config) error {
|
// ModuleDB 数据库模块
|
||||||
|
type ModuleDB struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleDB) Init() error {
|
||||||
|
cfg := config.Get()
|
||||||
// ETCD
|
// ETCD
|
||||||
if err := etcd.Init(cfg.DB.Etcd.Address); err != nil {
|
if err := etcd.Init(cfg.DB.Etcd.Address); err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -13,8 +19,13 @@ func (p *Program) initDB(cfg *config.Config) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Program) stopDB() error {
|
func (p *ModuleDB) Start() error {
|
||||||
_ = etcd.Close()
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ModuleDB) Stop() error {
|
||||||
|
if err := etcd.Close(); err != nil {
|
||||||
|
log.Errorf("close etcd failed: %v", err)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
27
Server/scene/app/grpc.go
Normal file
27
Server/scene/app/grpc.go
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"common/net/grpc/service"
|
||||||
|
"scene/config"
|
||||||
|
"scene/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
|
||||||
|
}
|
||||||
@@ -4,8 +4,8 @@ app:
|
|||||||
log:
|
log:
|
||||||
debug: true
|
debug: true
|
||||||
level: "debug"
|
level: "debug"
|
||||||
maxSize: 100
|
maxSize: 10
|
||||||
maxBackups: 3
|
maxBackups: 100
|
||||||
maxAge: 7
|
maxAge: 7
|
||||||
|
|
||||||
db:
|
db:
|
||||||
|
|||||||
19
Server/scene/config/config.prod.yaml
Normal file
19
Server/scene/config/config.prod.yaml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
app:
|
||||||
|
name: "scene-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: 8504
|
||||||
|
ttl: 20
|
||||||
Reference in New Issue
Block a user