backend.go 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. package backend
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/logic/pre_job"
  7. "io/ioutil"
  8. "net/http"
  9. "sync"
  10. "time"
  11. "github.com/ChineseSubFinder/ChineseSubFinder/pkg"
  12. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/local_http_proxy_server"
  13. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/settings"
  14. "github.com/ChineseSubFinder/ChineseSubFinder/frontend/dist"
  15. "github.com/gin-contrib/cors"
  16. "github.com/gin-gonic/gin"
  17. "github.com/sirupsen/logrus"
  18. "github.com/ChineseSubFinder/ChineseSubFinder/pkg/logic/cron_helper"
  19. )
  20. type BackEnd struct {
  21. logger *logrus.Logger
  22. cronHelper *cron_helper.CronHelper
  23. httpPort int
  24. running bool
  25. srv *http.Server
  26. locker sync.Mutex
  27. restartSignal chan interface{}
  28. preJob *pre_job.PreJob
  29. }
  30. func NewBackEnd(
  31. logger *logrus.Logger,
  32. cronHelper *cron_helper.CronHelper,
  33. httpPort int,
  34. restartSignal chan interface{}) *BackEnd {
  35. return &BackEnd{
  36. logger: logger,
  37. cronHelper: cronHelper,
  38. httpPort: httpPort,
  39. restartSignal: restartSignal,
  40. }
  41. }
  42. func (b *BackEnd) start() {
  43. defer b.locker.Unlock()
  44. b.locker.Lock()
  45. if b.running == true {
  46. b.logger.Debugln("Http Server is already running")
  47. return
  48. }
  49. b.running = true
  50. // ----------------------------------------
  51. // 设置代理
  52. err := local_http_proxy_server.SetProxyInfo(settings.Get().AdvancedSettings.ProxySettings.GetInfos())
  53. if err != nil {
  54. b.logger.Errorln("Set Local Http Proxy Server Error:", err)
  55. return
  56. }
  57. // -----------------------------------------
  58. // 设置跨域
  59. gin.SetMode(gin.ReleaseMode)
  60. gin.DefaultWriter = ioutil.Discard
  61. engine := gin.Default()
  62. // 默认所有都通过
  63. engine.Use(cors.Default())
  64. // 初始化路由
  65. b.preJob = pre_job.NewPreJob(b.logger)
  66. cbBase, v1Router := InitRouter(engine, b.cronHelper, b.restartSignal, b.preJob)
  67. // -----------------------------------------
  68. // 静态文件服务器
  69. engine.GET("/", func(c *gin.Context) {
  70. c.Header("content-type", "text/html;charset=utf-8")
  71. c.String(http.StatusOK, string(dist.SpaIndexHtml))
  72. })
  73. engine.StaticFS(dist.SpaFolderJS, dist.Assets(dist.SpaFolderName+dist.SpaFolderJS, dist.SpaJS))
  74. engine.StaticFS(dist.SpaFolderCSS, dist.Assets(dist.SpaFolderName+dist.SpaFolderCSS, dist.SpaCSS))
  75. engine.StaticFS(dist.SpaFolderFonts, dist.Assets(dist.SpaFolderName+dist.SpaFolderFonts, dist.SpaFonts))
  76. engine.StaticFS(dist.SpaFolderIcons, dist.Assets(dist.SpaFolderName+dist.SpaFolderIcons, dist.SpaIcons))
  77. engine.StaticFS(dist.SpaFolderImages, dist.Assets(dist.SpaFolderName+dist.SpaFolderImages, dist.SpaImages))
  78. // -----------------------------------------
  79. // 用于预览视频和字幕的静态文件服务
  80. previewCacheFolder, err := pkg.GetVideoAndSubPreviewCacheFolder()
  81. if err != nil {
  82. b.logger.Errorln("GetVideoAndSubPreviewCacheFolder Error:", err)
  83. return
  84. }
  85. engine.StaticFS("/static/preview", http.Dir(previewCacheFolder))
  86. // -----------------------------------------
  87. // api 服务
  88. engine.Any("/api", func(c *gin.Context) {
  89. c.Redirect(http.StatusMovedPermanently, "/")
  90. })
  91. // listen and serve on 0.0.0.0:8080(default)
  92. b.srv = &http.Server{
  93. Addr: fmt.Sprintf(":%d", b.httpPort),
  94. Handler: engine,
  95. }
  96. go func() {
  97. b.doPreJob()
  98. b.doCornJob()
  99. }()
  100. // 启动 http server
  101. go func() {
  102. b.logger.Infoln("Try Start Http Server At Port", b.httpPort)
  103. if err := b.srv.ListenAndServe(); err != nil && errors.Is(err, http.ErrServerClosed) == false {
  104. b.logger.Errorln("Start Server Error:", err)
  105. }
  106. defer func() {
  107. cbBase.Close()
  108. v1Router.Close()
  109. }()
  110. }()
  111. }
  112. func (b *BackEnd) Restart() {
  113. stopFunc := func() {
  114. b.locker.Lock()
  115. defer func() {
  116. b.locker.Unlock()
  117. }()
  118. if b.running == false {
  119. b.logger.Debugln("Http Server is not running")
  120. return
  121. }
  122. b.running = false
  123. exitOk := make(chan interface{}, 1)
  124. defer close(exitOk)
  125. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
  126. defer cancel()
  127. go func() {
  128. if err := b.srv.Shutdown(ctx); err != nil {
  129. b.logger.Errorln("Http Server Shutdown:", err)
  130. }
  131. exitOk <- true
  132. }()
  133. select {
  134. case <-ctx.Done():
  135. b.logger.Warningln("Http Server Shutdown timeout of 5 seconds.")
  136. case <-exitOk:
  137. b.logger.Infoln("Http Server Shutdown Successfully")
  138. }
  139. b.logger.Infoln("Http Server Shutdown Done.")
  140. }
  141. for {
  142. select {
  143. case <-b.restartSignal:
  144. {
  145. stopFunc()
  146. b.start()
  147. }
  148. }
  149. }
  150. }
  151. // doPreJob 前置的任务,热修复、字幕修改文件名格式、提前下载好浏览器
  152. func (b *BackEnd) doPreJob() {
  153. if settings.Get().UserInfo.Username == "" || settings.Get().UserInfo.Password == "" {
  154. // 如果没有完成,那么就不执行初始化
  155. b.logger.Infoln("Need do Setup, then do PreJob")
  156. } else {
  157. // 启动程序只会执行一次,用 Once 控制
  158. // 前置的任务,热修复、字幕修改文件名格式、提前下载好浏览器
  159. if settings.Get().SpeedDevMode == true {
  160. return
  161. }
  162. if pkg.LiteMode() == false {
  163. return
  164. }
  165. b.logger.Infoln("Setup is Done")
  166. b.logger.Infoln("PreJob Will Start...")
  167. // 不启用 Chrome 相关操作
  168. err := b.preJob.HotFix().ChangeSubNameFormat().Wait()
  169. if err != nil {
  170. b.logger.Errorln("pre_job", err)
  171. }
  172. }
  173. }
  174. // doCornJob 定时任务
  175. func (b *BackEnd) doCornJob() {
  176. // 需要使用 go 来执行,因为这个函数是阻塞的
  177. // 启动定时任务
  178. if settings.Get().UserInfo.Username == "" || settings.Get().UserInfo.Password == "" {
  179. // 如果没有完成,那么就不开启
  180. b.logger.Infoln("Need do Setup, then do CornJob")
  181. } else {
  182. // 是否完成了 Setup,如果完成了,那么就开启第一次的扫描
  183. go func() {
  184. b.logger.Infoln("Setup is Done")
  185. // settings.Get().CommonSettings.RunScanAtStartUp 取消开启就扫描的逻辑
  186. b.cronHelper.Start(false)
  187. }()
  188. }
  189. }