serv_http.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. // package serv_http -- востроенный HTTP-сервер
  2. package serv_http
  3. import (
  4. "fmt"
  5. "log"
  6. "os"
  7. "sync"
  8. "time"
  9. "github.com/gofiber/fiber/v2"
  10. "github.com/gofiber/fiber/v2/middleware/cache"
  11. "github.com/gofiber/fiber/v2/middleware/compress"
  12. "github.com/gofiber/fiber/v2/utils"
  13. "github.com/gofiber/template/html/v2"
  14. "git.p78su.freemyip.com/svi/gostore/pkg/serv_http/router_anonym"
  15. "git.p78su.freemyip.com/svi/gostore/pkg/types"
  16. )
  17. // ServHttp -- встроенный HTTP-сервер
  18. type ServHttp struct {
  19. serv types.IService
  20. fiberApp *fiber.App
  21. port string
  22. store types.IStore
  23. anonym *router_anonym.RouterAnonym
  24. block sync.RWMutex
  25. isWork bool // Признак работы
  26. }
  27. var IsBad_ bool // Для тестов
  28. // NewServHttp -- возвращает новый HTTP-сервер
  29. func NewServHttp(serv types.IService) (types.IServHttp, error) {
  30. if IsBad_ {
  31. return nil, fmt.Errorf("NewServHttp(): IsBad_==true")
  32. }
  33. if serv == nil {
  34. return nil, fmt.Errorf("NewServHttp(): IService==nil")
  35. }
  36. port := os.Getenv("STORE_HTTP_PORT")
  37. if port == "" {
  38. return nil, fmt.Errorf("NewServHttp(): env STORE_HTTP_PORT not set")
  39. }
  40. engineTmpl := html.New("./static/tmpl", ".tmpl.html")
  41. appConf := fiber.Config{
  42. Prefork: false,
  43. ServerHeader: "GoStore",
  44. StrictRouting: false,
  45. CaseSensitive: false,
  46. Immutable: false,
  47. UnescapePath: false,
  48. ETag: false,
  49. BodyLimit: 10_000_000,
  50. Concurrency: 0,
  51. Views: engineTmpl,
  52. ViewsLayout: "",
  53. PassLocalsToViews: false,
  54. ReadTimeout: time.Second * 60,
  55. WriteTimeout: time.Second * 60,
  56. IdleTimeout: time.Second * 10,
  57. ReadBufferSize: 0,
  58. WriteBufferSize: 0,
  59. CompressedFileSuffix: ".fiber.gz",
  60. ProxyHeader: "",
  61. GETOnly: false,
  62. // ErrorHandler: func(*fiber.Ctx, error) error { panic("not implemented") },
  63. DisableKeepalive: false,
  64. DisableDefaultDate: false,
  65. DisableDefaultContentType: false,
  66. DisableHeaderNormalizing: false,
  67. DisableStartupMessage: false,
  68. AppName: "GoStore",
  69. StreamRequestBody: false,
  70. DisablePreParseMultipartForm: false,
  71. ReduceMemoryUsage: false,
  72. // JSONEncoder: func(interface{}) ([]byte, error) { panic("not implemented") },
  73. // JSONDecoder: func([]byte, interface{}) error { panic("not implemented") },
  74. // XMLEncoder: func(interface{}) ([]byte, error) { panic("not implemented") },
  75. Network: "tcp4",
  76. EnableTrustedProxyCheck: false,
  77. TrustedProxies: []string{},
  78. EnableIPValidation: false,
  79. EnablePrintRoutes: true,
  80. // ColorScheme: fiber.Colors{
  81. // Black: "",
  82. // Red: "",
  83. // Green: "",
  84. // Yellow: "",
  85. // Blue: "",
  86. // Magenta: "",
  87. // Cyan: "",
  88. // White: "",
  89. // Reset: "",
  90. // },
  91. // RequestMethods: []string{},
  92. EnableSplittingOnParsers: false,
  93. }
  94. app := fiber.New(appConf)
  95. app.Static("/static", "./static")
  96. compressConf := compress.Config{
  97. Level: compress.LevelBestCompression,
  98. }
  99. app.Use(compress.New(compressConf))
  100. cacheConf := cache.Config{
  101. Next: nil,
  102. Expiration: 30 * time.Minute,
  103. CacheHeader: "X-Cache",
  104. CacheControl: true,
  105. KeyGenerator: func(c *fiber.Ctx) string {
  106. return utils.CopyString(c.Path())
  107. },
  108. ExpirationGenerator: nil,
  109. StoreResponseHeaders: false,
  110. Storage: nil,
  111. MaxBytes: 0,
  112. Methods: []string{fiber.MethodGet, fiber.MethodHead},
  113. }
  114. app.Use(cache.New(cacheConf))
  115. sf := &ServHttp{
  116. serv: serv,
  117. fiberApp: app,
  118. port: port,
  119. store: serv.Store(),
  120. }
  121. var err error
  122. sf.anonym, err = router_anonym.NewRouterAnonym(sf)
  123. if err != nil {
  124. return nil, err
  125. }
  126. sf.fiberApp.Get("/", sf.get)
  127. sf.serv.Wg().Add(1)
  128. sf.isWork = true
  129. go sf.close()
  130. return sf, nil
  131. }
  132. // Возвращает индексную страницу хранилища
  133. func (sf *ServHttp) get(ctx *fiber.Ctx) error {
  134. return ctx.Render("index", fiber.Map{})
  135. }
  136. // Service -- возвращает сервис
  137. func (sf *ServHttp) Service() types.IService {
  138. return sf.serv
  139. }
  140. // FiberApp -- возвращает fiber-приложение
  141. func (sf *ServHttp) FiberApp() *fiber.App {
  142. return sf.fiberApp
  143. }
  144. // Run -- запускает веб-сервер в работу
  145. func (sf *ServHttp) Run() error {
  146. defer sf.serv.CancelApp()
  147. err := sf.fiberApp.Listen(":" + sf.port)
  148. if err != nil {
  149. return fmt.Errorf("ServHttp.Run(): in listen port(%q), err=\n\t%w", sf.port, err)
  150. }
  151. return nil
  152. }
  153. func (sf *ServHttp) close() {
  154. <-sf.serv.Ctx().Done()
  155. sf.block.Lock()
  156. defer sf.block.Unlock()
  157. if !sf.isWork {
  158. return
  159. }
  160. sf.isWork = false
  161. err := sf.fiberApp.Shutdown()
  162. if err != nil {
  163. log.Printf("ServHttp.close(): in shutdown fiberApp, err=\n\t%v\n", err)
  164. }
  165. sf.serv.Wg().Done()
  166. }