// package serv_http -- востроенный HTTP-сервер package serv_http import ( "fmt" "os" "time" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/cache" "github.com/gofiber/fiber/v2/middleware/compress" "github.com/gofiber/fiber/v2/utils" "github.com/gofiber/template/html/v2" "git.p78su.freemyip.com/svi/gostore/internal/serv_http/router_anonym" "git.p78su.freemyip.com/svi/gostore/pkg/types" ) // ServHttp -- встроенный HTTP-сервер type ServHttp struct { serv types.IService fiberApp *fiber.App port string store types.IStore anonym *router_anonym.RouterAnonym } // NewServHttp -- возвращает новый HTTP-сервер func NewServHttp(serv types.IService) (*ServHttp, error) { if serv == nil { return nil, fmt.Errorf("NewServHttp(): IService==nil") } port := os.Getenv("STORE_HTTP_PORT") if port == "" { return nil, fmt.Errorf("NewServHttp(): env STORE_HTTP_PORT not set") } engineTmpl := html.New("./static/tmpl", ".tmpl.html") appConf := fiber.Config{ Prefork: false, ServerHeader: "GoStore", StrictRouting: false, CaseSensitive: false, Immutable: false, UnescapePath: false, ETag: false, BodyLimit: 10_000_000, Concurrency: 0, Views: engineTmpl, ViewsLayout: "", PassLocalsToViews: false, ReadTimeout: time.Second * 60, WriteTimeout: time.Second * 60, IdleTimeout: time.Second * 10, ReadBufferSize: 0, WriteBufferSize: 0, CompressedFileSuffix: ".fiber.gz", ProxyHeader: "", GETOnly: false, // ErrorHandler: func(*fiber.Ctx, error) error { panic("not implemented") }, DisableKeepalive: false, DisableDefaultDate: false, DisableDefaultContentType: false, DisableHeaderNormalizing: false, DisableStartupMessage: false, AppName: "GoStore", StreamRequestBody: false, DisablePreParseMultipartForm: false, ReduceMemoryUsage: false, // JSONEncoder: func(interface{}) ([]byte, error) { panic("not implemented") }, // JSONDecoder: func([]byte, interface{}) error { panic("not implemented") }, // XMLEncoder: func(interface{}) ([]byte, error) { panic("not implemented") }, Network: "tcp4", EnableTrustedProxyCheck: false, TrustedProxies: []string{}, EnableIPValidation: false, EnablePrintRoutes: true, // ColorScheme: fiber.Colors{ // Black: "", // Red: "", // Green: "", // Yellow: "", // Blue: "", // Magenta: "", // Cyan: "", // White: "", // Reset: "", // }, // RequestMethods: []string{}, EnableSplittingOnParsers: false, } app := fiber.New(appConf) app.Static("/static", "./static") compressConf := compress.Config{ Level: compress.LevelBestCompression, } app.Use(compress.New(compressConf)) cacheConf := cache.Config{ Next: nil, Expiration: 30 * time.Minute, CacheHeader: "X-Cache", CacheControl: true, KeyGenerator: func(c *fiber.Ctx) string { return utils.CopyString(c.Path()) }, ExpirationGenerator: nil, StoreResponseHeaders: false, Storage: nil, MaxBytes: 0, Methods: []string{fiber.MethodGet, fiber.MethodHead}, } app.Use(cache.New(cacheConf)) sf := &ServHttp{ serv: serv, fiberApp: app, port: port, store: serv.Store(), } var err error sf.anonym, err = router_anonym.NewRouterAnonym(sf) if err != nil { return nil, err } sf.fiberApp.Get("/", sf.get) sf.fiberApp.Post("/put/:login/:pass/:key", sf.postLogin, sf.postPut) sf.fiberApp.Post("/get/:login/:pass/:key", sf.postLogin, sf.postGet) sf.fiberApp.Post("/del/:login/:pass/:key", sf.postLogin, sf.postDel) sf.fiberApp.Post("/find/:login/:pass/:key", sf.postLogin, sf.postFind) return sf, nil } // Возвращает индексную страницу хранилища func (sf *ServHttp) get(ctx *fiber.Ctx) error { return ctx.Render("index", fiber.Map{}) } // Service -- возвращает сервис func (sf *ServHttp) Service() types.IService { return sf.serv } // FiberApp -- возвращает fiber-приложение func (sf *ServHttp) FiberApp() *fiber.App { return sf.fiberApp } type ListValRequest struct { Val_ []string `json:"val" form:"val"` } // postFind -- возвращает список ключей по префиксу func (sf *ServHttp) postFind(ctx *fiber.Ctx) error { key := ctx.Params("key") lstKey, err := sf.store.Find(key) if err != nil { return fiber.NewError(40, "ServHttp.postFind(): in get keys by prefix from db") } return ctx.JSON(&ListValRequest{ Val_: lstKey, }) } type ValRequest struct { Val_ []byte `json:"val" form:"val"` } // postDel -- удаляет содержимое ключа func (sf *ServHttp) postDel(ctx *fiber.Ctx) error { key := ctx.Params("key") sf.store.Del(key) return nil } // postGet -- возвращает содержимое ключа func (sf *ServHttp) postGet(ctx *fiber.Ctx) error { key := ctx.Params("key") val, err := sf.store.Get(key) if err != nil { return fiber.NewError(30, "ServHttp.postGet(): in get val from db") } return ctx.JSON(&ValRequest{ Val_: val, }) } // postPut -- сохраняет содержимое ключа func (sf *ServHttp) postPut(ctx *fiber.Ctx) error { key := ctx.Params("key") req := &ValRequest{} if err := ctx.BodyParser(req); err != nil { return fiber.NewError(20, "ServHttp.postPut(): bad FORM") } err := sf.store.Put(key, req.Val_) if err != nil { return fiber.NewError(21, "ServHttp.postPut(): in put val on db") } return nil } // Run -- запускает веб-сервер в работу func (sf *ServHttp) Run() error { defer sf.serv.CancelApp() err := sf.fiberApp.Listen(":" + sf.port) if err != nil { return fmt.Errorf("ServHttp.Run(): in listen port(%q), err=\n\t%w", sf.port, err) } return nil } // Проверяет логин/пароль в запросе func (sf *ServHttp) postLogin(ctx *fiber.Ctx) error { // login := ctx.Params("login") // if login != sf.login { // return fiber.NewError(1, "ServHttp.postLogin(): bad login/pass") // } // pass := ctx.Params("pass") // if pass != sf.pass { // return fiber.NewError(2, "ServHttp.postLogin(): bad login/pass") // } key := ctx.Params("key") if key == "" { return fiber.NewError(3, "ServHttp.postLogin(): key is empty") } return ctx.Next() }