serv_http.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. // package serv_http -- востроенный HTTP-сервер
  2. package serv_http
  3. import (
  4. "fmt"
  5. "os"
  6. "time"
  7. "github.com/gofiber/fiber/v2"
  8. "github.com/gofiber/fiber/v2/middleware/cache"
  9. "github.com/gofiber/fiber/v2/middleware/compress"
  10. "github.com/gofiber/fiber/v2/utils"
  11. "github.com/gofiber/template/html/v2"
  12. "git.p78su.freemyip.com/svi/gostore/internal/serv_http/router_anonym"
  13. "git.p78su.freemyip.com/svi/gostore/pkg/types"
  14. )
  15. // ServHttp -- встроенный HTTP-сервер
  16. type ServHttp struct {
  17. serv types.IService
  18. fiberApp *fiber.App
  19. port string
  20. store types.IStore
  21. anonym *router_anonym.RouterAnonym
  22. }
  23. // NewServHttp -- возвращает новый HTTP-сервер
  24. func NewServHttp(serv types.IService) (*ServHttp, error) {
  25. if serv == nil {
  26. return nil, fmt.Errorf("NewServHttp(): IService==nil")
  27. }
  28. port := os.Getenv("STORE_HTTP_PORT")
  29. if port == "" {
  30. return nil, fmt.Errorf("NewServHttp(): env STORE_HTTP_PORT not set")
  31. }
  32. engineTmpl := html.New("./static/tmpl", ".tmpl.html")
  33. appConf := fiber.Config{
  34. Prefork: false,
  35. ServerHeader: "GoStore",
  36. StrictRouting: false,
  37. CaseSensitive: false,
  38. Immutable: false,
  39. UnescapePath: false,
  40. ETag: false,
  41. BodyLimit: 10_000_000,
  42. Concurrency: 0,
  43. Views: engineTmpl,
  44. ViewsLayout: "",
  45. PassLocalsToViews: false,
  46. ReadTimeout: time.Second * 60,
  47. WriteTimeout: time.Second * 60,
  48. IdleTimeout: time.Second * 10,
  49. ReadBufferSize: 0,
  50. WriteBufferSize: 0,
  51. CompressedFileSuffix: ".fiber.gz",
  52. ProxyHeader: "",
  53. GETOnly: false,
  54. // ErrorHandler: func(*fiber.Ctx, error) error { panic("not implemented") },
  55. DisableKeepalive: false,
  56. DisableDefaultDate: false,
  57. DisableDefaultContentType: false,
  58. DisableHeaderNormalizing: false,
  59. DisableStartupMessage: false,
  60. AppName: "GoStore",
  61. StreamRequestBody: false,
  62. DisablePreParseMultipartForm: false,
  63. ReduceMemoryUsage: false,
  64. // JSONEncoder: func(interface{}) ([]byte, error) { panic("not implemented") },
  65. // JSONDecoder: func([]byte, interface{}) error { panic("not implemented") },
  66. // XMLEncoder: func(interface{}) ([]byte, error) { panic("not implemented") },
  67. Network: "tcp4",
  68. EnableTrustedProxyCheck: false,
  69. TrustedProxies: []string{},
  70. EnableIPValidation: false,
  71. EnablePrintRoutes: true,
  72. // ColorScheme: fiber.Colors{
  73. // Black: "",
  74. // Red: "",
  75. // Green: "",
  76. // Yellow: "",
  77. // Blue: "",
  78. // Magenta: "",
  79. // Cyan: "",
  80. // White: "",
  81. // Reset: "",
  82. // },
  83. // RequestMethods: []string{},
  84. EnableSplittingOnParsers: false,
  85. }
  86. app := fiber.New(appConf)
  87. app.Static("/static", "./static")
  88. compressConf := compress.Config{
  89. Level: compress.LevelBestCompression,
  90. }
  91. app.Use(compress.New(compressConf))
  92. cacheConf := cache.Config{
  93. Next: nil,
  94. Expiration: 30 * time.Minute,
  95. CacheHeader: "X-Cache",
  96. CacheControl: true,
  97. KeyGenerator: func(c *fiber.Ctx) string {
  98. return utils.CopyString(c.Path())
  99. },
  100. ExpirationGenerator: nil,
  101. StoreResponseHeaders: false,
  102. Storage: nil,
  103. MaxBytes: 0,
  104. Methods: []string{fiber.MethodGet, fiber.MethodHead},
  105. }
  106. app.Use(cache.New(cacheConf))
  107. sf := &ServHttp{
  108. serv: serv,
  109. fiberApp: app,
  110. port: port,
  111. store: serv.Store(),
  112. }
  113. var err error
  114. sf.anonym, err = router_anonym.NewRouterAnonym(sf)
  115. if err != nil {
  116. return nil, err
  117. }
  118. sf.fiberApp.Get("/", sf.get)
  119. sf.fiberApp.Post("/put/:login/:pass/:key", sf.postLogin, sf.postPut)
  120. sf.fiberApp.Post("/get/:login/:pass/:key", sf.postLogin, sf.postGet)
  121. sf.fiberApp.Post("/del/:login/:pass/:key", sf.postLogin, sf.postDel)
  122. sf.fiberApp.Post("/find/:login/:pass/:key", sf.postLogin, sf.postFind)
  123. return sf, nil
  124. }
  125. // Возвращает индексную страницу хранилища
  126. func (sf *ServHttp) get(ctx *fiber.Ctx) error {
  127. return ctx.Render("index", fiber.Map{})
  128. }
  129. // Service -- возвращает сервис
  130. func (sf *ServHttp) Service() types.IService {
  131. return sf.serv
  132. }
  133. // FiberApp -- возвращает fiber-приложение
  134. func (sf *ServHttp) FiberApp() *fiber.App {
  135. return sf.fiberApp
  136. }
  137. type ListValRequest struct {
  138. Val_ []string `json:"val" form:"val"`
  139. }
  140. // postFind -- возвращает список ключей по префиксу
  141. func (sf *ServHttp) postFind(ctx *fiber.Ctx) error {
  142. key := ctx.Params("key")
  143. lstKey, err := sf.store.Find(key)
  144. if err != nil {
  145. return fiber.NewError(40, "ServHttp.postFind(): in get keys by prefix from db")
  146. }
  147. return ctx.JSON(&ListValRequest{
  148. Val_: lstKey,
  149. })
  150. }
  151. type ValRequest struct {
  152. Val_ []byte `json:"val" form:"val"`
  153. }
  154. // postDel -- удаляет содержимое ключа
  155. func (sf *ServHttp) postDel(ctx *fiber.Ctx) error {
  156. key := ctx.Params("key")
  157. sf.store.Del(key)
  158. return nil
  159. }
  160. // postGet -- возвращает содержимое ключа
  161. func (sf *ServHttp) postGet(ctx *fiber.Ctx) error {
  162. key := ctx.Params("key")
  163. val, err := sf.store.Get(key)
  164. if err != nil {
  165. return fiber.NewError(30, "ServHttp.postGet(): in get val from db")
  166. }
  167. return ctx.JSON(&ValRequest{
  168. Val_: val,
  169. })
  170. }
  171. // postPut -- сохраняет содержимое ключа
  172. func (sf *ServHttp) postPut(ctx *fiber.Ctx) error {
  173. key := ctx.Params("key")
  174. req := &ValRequest{}
  175. if err := ctx.BodyParser(req); err != nil {
  176. return fiber.NewError(20, "ServHttp.postPut(): bad FORM")
  177. }
  178. err := sf.store.Put(key, req.Val_)
  179. if err != nil {
  180. return fiber.NewError(21, "ServHttp.postPut(): in put val on db")
  181. }
  182. return nil
  183. }
  184. // Run -- запускает веб-сервер в работу
  185. func (sf *ServHttp) Run() error {
  186. defer sf.serv.CancelApp()
  187. err := sf.fiberApp.Listen(":" + sf.port)
  188. if err != nil {
  189. return fmt.Errorf("ServHttp.Run(): in listen port(%q), err=\n\t%w", sf.port, err)
  190. }
  191. return nil
  192. }
  193. // Проверяет логин/пароль в запросе
  194. func (sf *ServHttp) postLogin(ctx *fiber.Ctx) error {
  195. // login := ctx.Params("login")
  196. // if login != sf.login {
  197. // return fiber.NewError(1, "ServHttp.postLogin(): bad login/pass")
  198. // }
  199. // pass := ctx.Params("pass")
  200. // if pass != sf.pass {
  201. // return fiber.NewError(2, "ServHttp.postLogin(): bad login/pass")
  202. // }
  203. key := ctx.Params("key")
  204. if key == "" {
  205. return fiber.NewError(3, "ServHttp.postLogin(): key is empty")
  206. }
  207. return ctx.Next()
  208. }