boot.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. package boot
  2. import (
  3. "context"
  4. "filesdk"
  5. "os"
  6. "github.com/dgrijalva/jwt-go"
  7. redisLib "github.com/go-redis/redis/v8"
  8. "github.com/gogf/gf/v2/frame/g"
  9. "github.com/gogf/gf/v2/net/ghttp"
  10. "go.uber.org/dig"
  11. "gorm.io/gorm"
  12. "yx-dataset-server/app/bll"
  13. "yx-dataset-server/app/bll/impl"
  14. "yx-dataset-server/app/errors"
  15. "yx-dataset-server/library/auth"
  16. "yx-dataset-server/library/dingtalk"
  17. "yx-dataset-server/library/gplus"
  18. "yx-dataset-server/library/logger"
  19. "yx-dataset-server/library/middleware"
  20. "yx-dataset-server/library/ragflow"
  21. "yx-dataset-server/library/redis"
  22. "yx-dataset-server/library/utils"
  23. "yx-dataset-server/router"
  24. )
  25. // VERSION 定义应用版本号
  26. const VERSION = "1.0.0"
  27. func init() {
  28. // 初始化logger
  29. logger.Init(utils.GetConfig("common.run_mode").String())
  30. logger.SetVersion(VERSION)
  31. logger.SetTraceIdFunc(utils.NewTraceID)
  32. ctx := logger.NewTraceIDContext(context.Background(), utils.NewTraceID())
  33. Init(ctx)
  34. }
  35. // 初始化App,
  36. // TODO: 返回释放回调,暂时没调用
  37. func Init(ctx context.Context) func() {
  38. logger.Printf(ctx, "服务启动,运行模式:%s,版本号:%s,进程号:%d", utils.GetConfig("common.run_mode").String(), VERSION, os.Getpid())
  39. // 初始化依赖注入容器
  40. container, call := buildContainer(ctx)
  41. // 初始化路由注册
  42. s := g.Server()
  43. // 每个请求生成新的追踪Id,如果上下文件中没有trace-id
  44. s.Use(middleware.TraceIdMiddleware())
  45. if utils.GetConfig("prometheus.enable").Bool() {
  46. p := middleware.NewPrometheus("ghttp")
  47. p.Use(s)
  48. }
  49. // 统一处理内部错误
  50. s.Use(func(r *ghttp.Request) {
  51. r.Middleware.Next()
  52. if err := r.GetError(); err != nil {
  53. gplus.ResError(r, err)
  54. }
  55. })
  56. _ = auth.InitAuth(ctx, container)
  57. //_ = initJwtAuth(ctx, container)
  58. initFileSDK(ctx)
  59. router.InitRouters(s, container)
  60. // 启动时批量拉起所有钉钉卡片回复模式的机器人
  61. if err := container.Invoke(func(b bll.IRobotConfig) error {
  62. return b.RestartAllRobots(ctx)
  63. }); err != nil {
  64. logger.Printf(ctx, "启动钉钉机器人(卡片流式模式)失败:%v", err)
  65. }
  66. return func() {
  67. if call != nil {
  68. call()
  69. }
  70. }
  71. }
  72. // 初始化jwt认证,可以把相关配置放到config.toml中
  73. func initJwtAuth(ctx context.Context, container *dig.Container) error {
  74. var opts []auth.Option
  75. opts = append(opts, auth.SetExpired(utils.GetConfig("jwt.expired").Int()))
  76. opts = append(opts, auth.SetSigningKey([]byte(utils.GetConfig("jwt.signing_key").String())))
  77. opts = append(opts, auth.SetKeyfunc(func(t *jwt.Token) (interface{}, error) {
  78. if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
  79. return nil, errors.ErrInvalidToken
  80. }
  81. return []byte(utils.GetConfig("jwt.signing_key").String()), nil
  82. }))
  83. switch utils.GetConfig("jwt.signing_method").String() {
  84. case "HS256":
  85. opts = append(opts, auth.SetSigningMethod(jwt.SigningMethodHS256))
  86. case "HS384":
  87. opts = append(opts, auth.SetSigningMethod(jwt.SigningMethodHS384))
  88. case "HS512":
  89. opts = append(opts, auth.SetSigningMethod(jwt.SigningMethodHS512))
  90. }
  91. var store auth.Storer
  92. switch utils.GetConfig("jwt.store").String() {
  93. case "file":
  94. case "redis":
  95. //store = redis.NewStore(&redis.Config{
  96. // Addr: rcfg.Addr,
  97. // Password: rcfg.Password,
  98. // DB: cfg.RedisDB,
  99. // KeyPrefix: cfg.RedisPrefix,
  100. //})
  101. }
  102. return container.Provide(func() auth.Auther { return auth.New(store, opts...) })
  103. }
  104. // 初始化redis
  105. func initRedis(ctx context.Context, container *dig.Container) func() {
  106. addr := utils.GetConfig("redis.addr").String()
  107. password := utils.GetConfig("redis.password").String()
  108. db := utils.GetConfig("redis.db").Int()
  109. redisCli := redis.Init(ctx, addr, password, db)
  110. logger.Printf(ctx, "REDIS初始化成功,当前服务器[%s]", addr)
  111. // 注入redis client
  112. _ = container.Provide(func() *redisLib.Client {
  113. return redisCli.GetRedisClient()
  114. })
  115. // 将 Redis 作为钉钉 access_token 的 L2 持久化存储注入
  116. dingtalk.SetTokenStorage(dingtalk.NewRedisTokenStorage(redisCli.GetRedisClient(), ""))
  117. logger.Printf(ctx, "钉钉 access_token Redis 缓存已启用")
  118. return func() {
  119. _ = redisCli.Close
  120. }
  121. }
  122. // 初始化redis
  123. func initRagHttpClient(ctx context.Context, container *dig.Container) func() {
  124. addr := utils.GetConfig("ragFlow.base_url").String()
  125. apiKey := utils.GetConfig("ragFlow.api_key").String()
  126. ragClient := ragflow.Init(ctx, addr, apiKey)
  127. // 注入redis client
  128. _ = container.Provide(func() *ragflow.Client {
  129. return ragClient
  130. })
  131. return nil
  132. }
  133. // 初始化存储,目前只初始化gorm
  134. func initStore(ctx context.Context, container *dig.Container) (func(), error) {
  135. var storeCall func()
  136. db, err := initGorm()
  137. if err != nil {
  138. return storeCall, err
  139. }
  140. // 如果自动映射数据表
  141. if utils.GetConfig("gorm.enable_auto_migrate").Bool() {
  142. err = autoMigrate(db)
  143. if err != nil {
  144. return storeCall, err
  145. }
  146. }
  147. // 注入DB
  148. _ = container.Provide(func() *gorm.DB { return db })
  149. // 注入model接口
  150. _ = InjectModel(container)
  151. storeCall = func() {
  152. sqlDb, _ := db.DB()
  153. _ = sqlDb.Close()
  154. }
  155. logger.Printf(ctx, "MYSQL初始化成功, 服务器[%s], 数据库[%s]",
  156. utils.GetConfig("mysql.host"),
  157. utils.GetConfig("mysql.db_name"))
  158. return storeCall, nil
  159. }
  160. // 构建依赖注入容器
  161. func buildContainer(ctx context.Context) (*dig.Container, func()) {
  162. container := dig.New()
  163. // 初始化存储模块
  164. storeCall, err := initStore(ctx, container)
  165. if err != nil {
  166. panic(err)
  167. }
  168. // 初始化redis模块
  169. var redisCall func()
  170. if utils.GetConfig("redis.enable").Bool() {
  171. redisCall = initRedis(ctx, container)
  172. }
  173. initRagHttpClient(ctx, container)
  174. // 注入bll
  175. impl.Inject(container)
  176. return container, func() {
  177. if storeCall != nil {
  178. storeCall()
  179. }
  180. if redisCall != nil {
  181. redisCall()
  182. }
  183. }
  184. }
  185. func initFileSDK(ctx context.Context) {
  186. fileConfig := filesdk.Config{
  187. Host: utils.GetConfig("file_server.host").String(),
  188. }
  189. fileConfig.Init()
  190. }