backend.go 5.6 KB

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