serv_http.go 4.8 KB

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