backend.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  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. preJob: pre_job.NewPreJob(logger),
  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. 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. // 启动程序只会执行一次,用 Once 控制
  153. // 前置的任务,热修复、字幕修改文件名格式、提前下载好浏览器
  154. if settings.Get().SpeedDevMode == true {
  155. return
  156. }
  157. if pkg.LiteMode() == false {
  158. return
  159. }
  160. // 不启用 Chrome 相关操作
  161. err := b.preJob.HotFix().ChangeSubNameFormat().Wait()
  162. if err != nil {
  163. b.logger.Errorln("pre_job", err)
  164. }
  165. }
  166. // doCornJob 定时任务
  167. func (b *BackEnd) doCornJob() {
  168. // 需要使用 go 来执行,因为这个函数是阻塞的
  169. // 启动定时任务
  170. if settings.Get().UserInfo.Username == "" || settings.Get().UserInfo.Password == "" {
  171. // 如果没有完成,那么就不开启
  172. b.logger.Infoln("Need do Setup")
  173. } else {
  174. // 是否完成了 Setup,如果完成了,那么就开启第一次的扫描
  175. go func() {
  176. b.logger.Infoln("Setup is Done")
  177. b.cronHelper.Start(settings.Get().CommonSettings.RunScanAtStartUp)
  178. }()
  179. }
  180. }