P5 阶段交付物: - services/msg: 消息通知服务(NestJS) - notifications: 发送通知 + ES 全文检索 + search - config/elasticsearch.ts: ES Client 单例 - package.json: 补充 @opentelemetry/sdk-node + exporter-trace-otlp-http - services/push-gateway: WebSocket 推送网关(Go Gin) - internal/hub/hub.go: WebSocket 连接池管理(Register/Unregister/SendToUser) - internal/ws/handler.go: JWT 鉴权 + WebSocket 升级 + 内部推送 API - services/ai: AI 辅助服务(Python FastAPI) - /chat + /chat/stream(SSE 流式) - /generate/question + /optimize/expression - config.py: OpenAI 兼容 API 配置 - packages/shared-proto/proto/msg.proto: NotificationService 契约(send/search) - packages/shared-proto/proto/ai.proto: AiService 契约(含 stream 方法)
64 lines
1.4 KiB
Go
64 lines
1.4 KiB
Go
package main
|
||
|
||
import (
|
||
"context"
|
||
"log"
|
||
"net/http"
|
||
"os"
|
||
"os/signal"
|
||
"syscall"
|
||
"time"
|
||
|
||
"github.com/edu-cloud/push-gateway/internal/config"
|
||
"github.com/edu-cloud/push-gateway/internal/hub"
|
||
"github.com/edu-cloud/push-gateway/internal/ws"
|
||
"github.com/gin-gonic/gin"
|
||
)
|
||
|
||
func main() {
|
||
cfg := config.Load()
|
||
gin.SetMode(gin.ReleaseMode)
|
||
|
||
h := hub.NewHub()
|
||
wsHandler := ws.NewHandler(h, cfg.JWTSecret)
|
||
|
||
r := gin.New()
|
||
r.Use(gin.Recovery())
|
||
|
||
r.GET("/healthz", func(c *gin.Context) {
|
||
c.JSON(200, gin.H{"status": "ok", "service": "push-gateway"})
|
||
})
|
||
|
||
// WebSocket 升级端点
|
||
r.GET("/ws", wsHandler.HandleWebSocket)
|
||
|
||
// 内部推送 API(Msg 服务调用)
|
||
api := r.Group("/internal")
|
||
api.POST("/push", wsHandler.PushHandler)
|
||
|
||
srv := &http.Server{
|
||
Addr: ":" + cfg.Port,
|
||
Handler: r,
|
||
ReadTimeout: 10 * time.Second,
|
||
WriteTimeout: 60 * time.Second, // WebSocket 长连接
|
||
}
|
||
|
||
go func() {
|
||
log.Printf("Push Gateway listening on :%s", cfg.Port)
|
||
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||
log.Fatalf("listen: %s\n", err)
|
||
}
|
||
}()
|
||
|
||
quit := make(chan os.Signal, 1)
|
||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||
<-quit
|
||
log.Println("Shutting down Push Gateway...")
|
||
|
||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||
defer cancel()
|
||
if err := srv.Shutdown(ctx); err != nil {
|
||
log.Fatal("Server forced to shutdown:", err)
|
||
}
|
||
}
|