Diagnosing "credential not configured" required reading the source: the local config layer was a silent no-op when it found no file, and the import error named only environment variables even though config.yaml is now the normal place to configure this — sending operators to look in a file that was never the problem. Startup now logs which config.yaml was loaded, or that none was found and where it looked, followed by whether SYB credentials resolved and from which layer. Presence only, never values: server logs get pasted into tickets. The import error now names the file that was actually consulted and distinguishes "no config.yaml found" from "found it, but it has no syb credentials" — two problems with different fixes that previously produced identical text. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
202 lines
5.6 KiB
Go
202 lines
5.6 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"net/http"
|
|
"os"
|
|
"os/signal"
|
|
"time"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/go-admin-team/go-admin-core/config/source/file"
|
|
log "github.com/go-admin-team/go-admin-core/logger"
|
|
"github.com/go-admin-team/go-admin-core/sdk"
|
|
"github.com/go-admin-team/go-admin-core/sdk/api"
|
|
"github.com/go-admin-team/go-admin-core/sdk/config"
|
|
"github.com/go-admin-team/go-admin-core/sdk/pkg"
|
|
"github.com/pkg/errors"
|
|
"github.com/spf13/cobra"
|
|
|
|
"go-admin/app/admin/models"
|
|
"go-admin/app/admin/router"
|
|
goautodevice "go-admin/app/goauto/device"
|
|
"go-admin/app/jobs"
|
|
"go-admin/common/database"
|
|
"go-admin/common/global"
|
|
common "go-admin/common/middleware"
|
|
"go-admin/common/middleware/handler"
|
|
"go-admin/common/storage"
|
|
ext "go-admin/config"
|
|
)
|
|
|
|
var (
|
|
configYml string
|
|
apiCheck bool
|
|
StartCmd = &cobra.Command{
|
|
Use: "server",
|
|
Short: "Start API server",
|
|
Example: "go-admin server -c config/settings.yml",
|
|
SilenceUsage: true,
|
|
PreRun: func(cmd *cobra.Command, args []string) {
|
|
setup()
|
|
},
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
|
return run()
|
|
},
|
|
}
|
|
)
|
|
|
|
var AppRouters = make([]func(), 0)
|
|
|
|
func init() {
|
|
StartCmd.PersistentFlags().StringVarP(&configYml, "config", "c", "config/settings.yml", "Start server with provided configuration file")
|
|
StartCmd.PersistentFlags().BoolVarP(&apiCheck, "api", "a", false, "Start server with check api data")
|
|
|
|
//注册路由 fixme 其他应用的路由,在本目录新建文件放在init方法
|
|
AppRouters = append(AppRouters, router.InitRouter)
|
|
}
|
|
|
|
func setup() {
|
|
// 注入配置扩展项
|
|
config.ExtendConfig = &ext.ExtConfig
|
|
//1. 读取配置
|
|
config.Setup(
|
|
file.NewSource(file.WithPath(configYml)),
|
|
ext.ApplyLocalConfig,
|
|
ext.ApplyEnvironment,
|
|
ext.LogEffectiveConfig,
|
|
database.Setup,
|
|
storage.Setup,
|
|
)
|
|
//注册监听函数
|
|
queue := sdk.Runtime.GetMemoryQueue("")
|
|
queue.Register(global.LoginLog, models.SaveLoginLog)
|
|
queue.Register(global.OperateLog, models.SaveOperaLog)
|
|
queue.Register(global.ApiCheck, models.SaveSysApi)
|
|
go queue.Run()
|
|
|
|
usageStr := `starting api server...`
|
|
log.Info(usageStr)
|
|
}
|
|
|
|
func run() error {
|
|
if config.ApplicationConfig.Mode == pkg.ModeProd.String() {
|
|
gin.SetMode(gin.ReleaseMode)
|
|
}
|
|
initRouter()
|
|
|
|
for _, f := range AppRouters {
|
|
f()
|
|
}
|
|
offlineMonitorContext, stopOfflineMonitors := context.WithCancel(context.Background())
|
|
defer stopOfflineMonitors()
|
|
for _, db := range sdk.Runtime.GetDb() {
|
|
service := goautodevice.NewService(db)
|
|
go goautodevice.RunOfflineMonitor(
|
|
offlineMonitorContext, service, goautodevice.DefaultOfflineScan, goautodevice.DefaultOfflineThreshold,
|
|
func(err error) { log.Errorf("device offline monitor failed: %v", err) },
|
|
)
|
|
}
|
|
|
|
srv := &http.Server{
|
|
Addr: fmt.Sprintf("%s:%d", config.ApplicationConfig.Host, config.ApplicationConfig.Port),
|
|
Handler: sdk.Runtime.GetEngine(),
|
|
ReadTimeout: time.Duration(config.ApplicationConfig.ReadTimeout) * time.Second,
|
|
WriteTimeout: time.Duration(config.ApplicationConfig.WriterTimeout) * time.Second,
|
|
}
|
|
|
|
go func() {
|
|
jobs.InitJob()
|
|
jobs.Setup(sdk.Runtime.GetDb())
|
|
|
|
}()
|
|
|
|
if apiCheck {
|
|
var routers = sdk.Runtime.GetRouter()
|
|
q := sdk.Runtime.GetMemoryQueue("")
|
|
mp := make(map[string]interface{})
|
|
mp["List"] = routers
|
|
message, err := sdk.Runtime.GetStreamMessage("", global.ApiCheck, mp)
|
|
if err != nil {
|
|
log.Infof("GetStreamMessage error, %s \n", err.Error())
|
|
//日志报错错误,不中断请求
|
|
} else {
|
|
err = q.Append(message)
|
|
if err != nil {
|
|
log.Infof("Append message error, %s \n", err.Error())
|
|
}
|
|
}
|
|
}
|
|
|
|
go func() {
|
|
// 服务连接
|
|
if config.SslConfig.Enable {
|
|
if err := srv.ListenAndServeTLS(config.SslConfig.Pem, config.SslConfig.KeyStr); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
log.Fatal("listen: ", err)
|
|
}
|
|
} else {
|
|
if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
|
log.Fatal("listen: ", err)
|
|
}
|
|
}
|
|
}()
|
|
fmt.Println(pkg.Red(string(global.LogoContent)))
|
|
tip()
|
|
fmt.Println(pkg.Green("Server run at:"))
|
|
fmt.Printf("- Local: %s://localhost:%d/ \r\n", "http", config.ApplicationConfig.Port)
|
|
fmt.Printf("- Network: %s://%s:%d/ \r\n", "http", pkg.GetLocalHost(), config.ApplicationConfig.Port)
|
|
fmt.Println(pkg.Green("Swagger run at:"))
|
|
fmt.Printf("- Local: http://localhost:%d/swagger/admin/index.html \r\n", config.ApplicationConfig.Port)
|
|
fmt.Printf("- Network: %s://%s:%d/swagger/admin/index.html \r\n", "http", pkg.GetLocalHost(), config.ApplicationConfig.Port)
|
|
fmt.Printf("%s Enter Control + C Shutdown Server \r\n", pkg.GetCurrentTimeStr())
|
|
// 等待中断信号以优雅地关闭服务器(设置 5 秒的超时时间)
|
|
quit := make(chan os.Signal, 1)
|
|
signal.Notify(quit, os.Interrupt)
|
|
<-quit
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
|
defer cancel()
|
|
log.Info("Shutdown Server ... ")
|
|
|
|
if err := srv.Shutdown(ctx); err != nil {
|
|
log.Fatal("Server Shutdown:", err)
|
|
}
|
|
log.Info("Server exiting")
|
|
|
|
return nil
|
|
}
|
|
|
|
//var Router runtime.Router
|
|
|
|
func tip() {
|
|
usageStr := `欢迎使用 ` + pkg.Green(`go-admin `+global.Version) + ` 可以使用 ` + pkg.Red(`-h`) + ` 查看命令`
|
|
fmt.Printf("%s \n\n", usageStr)
|
|
}
|
|
|
|
func initRouter() {
|
|
var r *gin.Engine
|
|
h := sdk.Runtime.GetEngine()
|
|
if h == nil {
|
|
h = gin.New()
|
|
sdk.Runtime.SetEngine(h)
|
|
}
|
|
switch h.(type) {
|
|
case *gin.Engine:
|
|
r = h.(*gin.Engine)
|
|
default:
|
|
log.Fatal("not support other engine")
|
|
//os.Exit(-1)
|
|
}
|
|
if config.SslConfig.Enable {
|
|
r.Use(handler.TlsHandler())
|
|
}
|
|
//r.Use(middleware.Metrics())
|
|
r.Use(common.Sentinel()).
|
|
Use(common.RequestId(pkg.TrafficKey)).
|
|
Use(api.SetRequestLogger)
|
|
|
|
common.InitMiddleware(r)
|
|
|
|
}
|