// entry function package main import ( "context" "flag" "net/http" "os" "os/signal" "syscall" "time" "modelRT/alert" "modelRT/config" "modelRT/database" "modelRT/diagram" locker "modelRT/distributedlock" _ "modelRT/docs" "modelRT/handler" "modelRT/logger" "modelRT/middleware" "modelRT/pool" "modelRT/router" realtimedata "modelRT/real-time-data" "github.com/gin-gonic/gin" "github.com/panjf2000/ants/v2" swaggerFiles "github.com/swaggo/files" ginSwagger "github.com/swaggo/gin-swagger" "gorm.io/gorm" ) var limiter *middleware.Limiter func init() { limiter = middleware.NewLimiter(10, 1*time.Minute) // 设置限流器,允许每分钟最多请求10次 } var ( modelRTConfigDir = flag.String("modelRT_config_dir", "./config", "config file dir of model runtime service") modelRTConfigName = flag.String("modelRT_config_name", "config", "config file name of model runtime service") modelRTConfigType = flag.String("modelRT_config_type", "yaml", "config file type of model runtime service") ) var ( modelRTConfig config.ModelRTConfig postgresDBClient *gorm.DB alertManager *alert.EventManager ) // TODO 使用 wire 依赖注入管理 DVIE 面板注册的 panel func main() { flag.Parse() ctx := context.TODO() // init logger logger.InitLoggerInstance(modelRTConfig.LoggerConfig) modelRTConfig = config.ReadAndInitConfig(*modelRTConfigDir, *modelRTConfigName, *modelRTConfigType) // init postgresDBClient postgresDBClient = database.InitPostgresDBInstance(ctx, modelRTConfig.PostgresDBURI) defer func() { sqlDB, err := postgresDBClient.DB() if err != nil { panic(err) } sqlDB.Close() }() // init alert manager _ = alert.InitAlertEventManager() // init model parse ants pool parsePool, err := ants.NewPoolWithFunc(modelRTConfig.ParseConcurrentQuantity, pool.ParseFunc) if err != nil { logger.Error(ctx, "init concurrent parse task pool failed", "error", err) panic(err) } defer parsePool.Release() storageClient := diagram.InitClientInstance(modelRTConfig.StorageRedisConfig) defer storageClient.Close() lockerClient := locker.InitClientInstance(modelRTConfig.LockerRedisConfig) defer lockerClient.Close() // init anchor param ants pool anchorRealTimePool, err := pool.AnchorPoolInit(modelRTConfig.RTDReceiveConcurrentQuantity) if err != nil { logger.Error(ctx, "init concurrent anchor param task pool failed", "error", err) panic(err) } defer anchorRealTimePool.Release() // init cancel context cancelCtx, cancel := context.WithCancel(ctx) defer cancel() // init real time data receive channel go realtimedata.ReceiveChan(cancelCtx) postgresDBClient.Transaction(func(tx *gorm.DB) error { // load circuit diagram from postgres componentTypeMap, err := database.QueryCircuitDiagramComponentFromDB(cancelCtx, tx, parsePool) if err != nil { logger.Error(ctx, "load circuit diagrams from postgres failed", "error", err) panic(err) } // TODO 暂时屏蔽完成 swagger 启动测试 tree, err := database.QueryTopologicFromDB(ctx, tx, componentTypeMap) if err != nil { logger.Error(ctx, "load topologic info from postgres failed", "error", err) panic(err) } diagram.GlobalTree = tree return nil }) // TODO 完成订阅数据分析 // TODO 暂时屏蔽完成 swagger 启动测试 // go realtimedata.RealTimeDataComputer(ctx, nil, []string{}, "") engine := gin.New() router.RegisterRoutes(engine) server := http.Server{ Addr: ":8080", Handler: engine, } // creating a System Signal Receiver done := make(chan os.Signal, 10) signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM) go func() { <-done if err := server.Shutdown(context.Background()); err != nil { logger.Error(ctx, "ShutdownServerError", "err", err) } }() logger.Info(ctx, "Starting ModelRT server...") err = server.ListenAndServe() if err != nil { if err == http.ErrServerClosed { // the service receives the shutdown signal normally and then closes logger.Info(ctx, "Server closed under request") } else { // abnormal shutdown of service logger.Error(ctx, "Server closed unexpected", "err", err) } } // real time data api engine.GET("/ws/rtdatas", handler.RealTimeDataReceivehandler) // anchor api engine.POST("/model/anchor_replace", handler.ComponentAnchorReplaceHandler) // alert api engine.GET("/alert/events/query", handler.QueryAlertEventHandler) // real time data api engine.GET("/rt/datas/query", handler.QueryRealTimeDataHandler) // dashborad api dashboard := engine.Group("/dashboard", limiter.Middleware) { dashboard.GET("/load", nil) dashboard.GET("/query", nil) dashboard.POST("/create", nil) dashboard.POST("/update", nil) dashboard.POST("/delete", nil) } // engine.Group() // Swagger UI engine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler)) // 注册 Swagger UI 路由 // docs.SwaggerInfo.BasePath = "/model" // v1 := engine.Group("/api/v1") // { // eg := v1.Group("/example") // { // eg.GET("/helloworld", Helloworld) // } // } // start route with 8080 port engine.Run(":8080") // Redis hashmap 母线模型、异步电动机模型 // kv key name value busx }