startup.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. package main
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "math/rand/v2"
  7. "net/http"
  8. "os"
  9. "path/filepath"
  10. "strings"
  11. "sync"
  12. "time"
  13. "github.com/gin-gonic/gin"
  14. "github.com/joho/godotenv"
  15. "github.com/labring/aiproxy/core/common"
  16. "github.com/labring/aiproxy/core/common/balance"
  17. "github.com/labring/aiproxy/core/common/config"
  18. "github.com/labring/aiproxy/core/common/conv"
  19. "github.com/labring/aiproxy/core/common/notify"
  20. "github.com/labring/aiproxy/core/common/pprof"
  21. "github.com/labring/aiproxy/core/middleware"
  22. "github.com/labring/aiproxy/core/model"
  23. "github.com/labring/aiproxy/core/router"
  24. log "github.com/sirupsen/logrus"
  25. )
  26. func initializeServices(pprofPort int) error {
  27. initializePprof(pprofPort)
  28. initializeNotifier()
  29. if err := common.InitRedisClient(); err != nil {
  30. return err
  31. }
  32. if err := initializeBalance(); err != nil {
  33. return err
  34. }
  35. if err := model.InitDB(); err != nil {
  36. return err
  37. }
  38. if err := initializeOptionAndCaches(); err != nil {
  39. return err
  40. }
  41. return model.InitLogDB(int(config.GetCleanLogBatchSize()))
  42. }
  43. func initializePprof(pprofPort int) {
  44. go func() {
  45. err := pprof.RunPprofServer(pprofPort)
  46. if err != nil {
  47. log.Errorf("run pprof server error: %v", err)
  48. }
  49. }()
  50. }
  51. func initializeBalance() error {
  52. sealosJwtKey := os.Getenv("SEALOS_JWT_KEY")
  53. if sealosJwtKey == "" {
  54. log.Info("SEALOS_JWT_KEY is not set, balance will not be enabled")
  55. return nil
  56. }
  57. log.Info("SEALOS_JWT_KEY is set, balance will be enabled")
  58. return balance.InitSealos(sealosJwtKey, os.Getenv("SEALOS_ACCOUNT_URL"))
  59. }
  60. func initializeNotifier() {
  61. feishuWh := os.Getenv("NOTIFY_FEISHU_WEBHOOK")
  62. if feishuWh != "" {
  63. notify.SetDefaultNotifier(notify.NewFeishuNotify(feishuWh))
  64. log.Info("NOTIFY_FEISHU_WEBHOOK is set, notifier will be use feishu")
  65. }
  66. }
  67. func initializeOptionAndCaches() error {
  68. log.Info("starting init config and channel")
  69. if err := model.InitOption2DB(); err != nil {
  70. return err
  71. }
  72. return model.InitModelConfigAndChannelCache()
  73. }
  74. func startSyncServices(ctx context.Context, wg *sync.WaitGroup) {
  75. wg.Add(2)
  76. go model.SyncOptions(ctx, wg, time.Second*5)
  77. go model.SyncModelConfigAndChannelCache(ctx, wg, time.Second*10)
  78. }
  79. func setupHTTPServer(listen string) (*http.Server, *gin.Engine) {
  80. server := gin.New()
  81. server.Use(
  82. middleware.GinRecoveryHandler,
  83. middleware.NewLog(log.StandardLogger()),
  84. middleware.RequestIDMiddleware,
  85. middleware.CORS(),
  86. )
  87. router.SetRouter(server)
  88. listenEnv := os.Getenv("LISTEN")
  89. if listenEnv != "" {
  90. listen = listenEnv
  91. }
  92. return &http.Server{
  93. Addr: listen,
  94. ReadHeaderTimeout: 10 * time.Second,
  95. Handler: server,
  96. }, server
  97. }
  98. var loadedEnvFiles []string
  99. func loadEnv() {
  100. envfiles := []string{
  101. ".env",
  102. ".env.local",
  103. ".env.aiproxy.local",
  104. }
  105. for _, envfile := range envfiles {
  106. absPath, err := filepath.Abs(envfile)
  107. if err != nil {
  108. panic(
  109. fmt.Sprintf(
  110. "failed to get absolute path of env file: %s, error: %s",
  111. envfile,
  112. err.Error(),
  113. ),
  114. )
  115. }
  116. file, err := os.Stat(absPath)
  117. if err != nil {
  118. continue
  119. }
  120. if file.IsDir() {
  121. continue
  122. }
  123. if err := godotenv.Overload(absPath); err != nil {
  124. panic(fmt.Sprintf("failed to load env file: %s, error: %s", absPath, err.Error()))
  125. }
  126. loadedEnvFiles = append(loadedEnvFiles, absPath)
  127. }
  128. }
  129. func printLoadedEnvFiles() {
  130. for _, envfile := range loadedEnvFiles {
  131. log.Infof("loaded env file: %s", envfile)
  132. }
  133. }
  134. func listenAndServe(srv *http.Server) {
  135. if err := srv.ListenAndServe(); err != nil &&
  136. !errors.Is(err, http.ErrServerClosed) {
  137. log.Fatal("failed to start HTTP server: " + err.Error())
  138. }
  139. }
  140. const (
  141. keyChars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
  142. )
  143. func generateAdminKey() string {
  144. key := make([]byte, 48)
  145. for i := range key {
  146. key[i] = keyChars[rand.IntN(len(keyChars))]
  147. }
  148. return conv.BytesToString(key)
  149. }
  150. func writeToEnvFile(envFile, key, value string) error {
  151. var lines []string
  152. if content, err := os.ReadFile(envFile); err == nil {
  153. lines = strings.Split(string(content), "\n")
  154. }
  155. keyPrefix := key + "="
  156. found := false
  157. for i, line := range lines {
  158. if strings.HasPrefix(line, keyPrefix) {
  159. lines[i] = key + "=" + value
  160. found = true
  161. break
  162. }
  163. }
  164. if !found {
  165. lines = append(lines, key+"="+value)
  166. }
  167. content := strings.Join(lines, "\n")
  168. if !strings.HasSuffix(content, "\n") && content != "" {
  169. content += "\n"
  170. }
  171. return os.WriteFile(envFile, []byte(content), 0o600)
  172. }
  173. func ensureAdminKey() error {
  174. if config.AdminKey != "" {
  175. log.Info("AdminKey is already set")
  176. return nil
  177. }
  178. log.Info("AdminKey is not set, generating new AdminKey...")
  179. config.AdminKey = generateAdminKey()
  180. envFile := ".env.aiproxy.local"
  181. absEnvFile, err := filepath.Abs(envFile)
  182. if err == nil {
  183. envFile = absEnvFile
  184. }
  185. if err := writeToEnvFile(envFile, "ADMIN_KEY", config.AdminKey); err != nil {
  186. return fmt.Errorf("failed to write AdminKey to %s: %w", envFile, err)
  187. }
  188. log.Info("Generated new AdminKey and saved to " + envFile)
  189. return nil
  190. }