serv_http.go 5.8 KB

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