You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
172 lines
3.8 KiB
172 lines
3.8 KiB
3 years ago
|
package httpclient
|
||
3 years ago
|
|
||
|
import (
|
||
3 years ago
|
"fmt"
|
||
3 years ago
|
"strconv"
|
||
3 years ago
|
"sync"
|
||
3 years ago
|
"time"
|
||
|
|
||
3 years ago
|
"github.com/mailru/easyjson"
|
||
3 years ago
|
"github.com/valyala/fasthttp"
|
||
3 years ago
|
|
||
|
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost"
|
||
|
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/data"
|
||
|
"code.tokarch.uk/mainnika/nikita-tokarch-uk/pkg/ghost/params"
|
||
3 years ago
|
)
|
||
3 years ago
|
|
||
3 years ago
|
var _ ghost.Client = (*HTTPClient)(nil)
|
||
3 years ago
|
|
||
3 years ago
|
// Ghost content data URIs:
|
||
|
const (
|
||
3 years ago
|
ghostAPIPrefix = "/ghost/api/v3/"
|
||
3 years ago
|
ghostAPIGetPosts = ghostAPIPrefix + "content/posts/"
|
||
3 years ago
|
ghostAPIGetPostBySlug = ghostAPIPrefix + "content/posts/slug/%s/"
|
||
3 years ago
|
ghostAPIGetPageBySlug = ghostAPIPrefix + "content/pages/slug/%s/"
|
||
3 years ago
|
)
|
||
|
|
||
|
// HTTPClient implements the ghost http client
|
||
|
type HTTPClient struct {
|
||
|
QueryTimeout time.Duration
|
||
|
ContentKey string
|
||
|
Addr string
|
||
|
Secured bool
|
||
3 years ago
|
Headers map[string]string
|
||
3 years ago
|
|
||
|
client *fasthttp.HostClient
|
||
3 years ago
|
|
||
|
setupClientOnce sync.Once
|
||
3 years ago
|
}
|
||
|
|
||
|
// setupClient creates the default http client
|
||
|
func (g *HTTPClient) setupClient() {
|
||
|
|
||
|
g.client = &fasthttp.HostClient{
|
||
|
Addr: g.Addr,
|
||
|
IsTLS: g.Secured,
|
||
|
|
||
|
DisableHeaderNamesNormalizing: true,
|
||
|
DisablePathNormalizing: true,
|
||
|
}
|
||
|
}
|
||
3 years ago
|
|
||
|
// doQuery does the method and unmarshals the result into the easyjson Unmarshaler
|
||
3 years ago
|
func (g *HTTPClient) doQuery(path string, v easyjson.Unmarshaler, params params.Params) (err error) {
|
||
3 years ago
|
|
||
|
g.setupClientOnce.Do(g.setupClient)
|
||
|
|
||
|
req := fasthttp.AcquireRequest()
|
||
|
res := fasthttp.AcquireResponse()
|
||
|
defer func() {
|
||
|
fasthttp.ReleaseResponse(res)
|
||
|
fasthttp.ReleaseRequest(req)
|
||
|
}()
|
||
|
|
||
3 years ago
|
g.setupRequest(path, req)
|
||
3 years ago
|
g.applyParams(params, req)
|
||
3 years ago
|
|
||
|
err = g.client.DoTimeout(req, res, g.QueryTimeout)
|
||
|
if err != nil {
|
||
|
return
|
||
|
}
|
||
|
if res.StatusCode() != fasthttp.StatusOK {
|
||
|
return fmt.Errorf("non OK status code: %d", res.StatusCode())
|
||
|
}
|
||
|
|
||
|
resBytes := res.Body()
|
||
|
if resBytes == nil && v == nil {
|
||
|
return fmt.Errorf("nothing to unmarshal")
|
||
|
}
|
||
|
if resBytes == nil {
|
||
|
return
|
||
|
}
|
||
|
|
||
|
err = easyjson.Unmarshal(resBytes, v)
|
||
|
|
||
3 years ago
|
return
|
||
|
}
|
||
|
|
||
3 years ago
|
// setupRequest does the necessary initial configuration to the http request
|
||
|
func (g *HTTPClient) setupRequest(path string, req *fasthttp.Request) {
|
||
|
|
||
|
uri := req.URI()
|
||
|
|
||
|
scheme := "http"
|
||
|
if g.Secured {
|
||
|
scheme = "https"
|
||
|
}
|
||
|
|
||
|
uri.SetHost(g.Addr)
|
||
|
uri.SetPath(path)
|
||
|
uri.SetScheme(scheme)
|
||
|
|
||
|
uri.QueryArgs().Add("key", g.ContentKey)
|
||
|
|
||
|
for hKey, hValue := range g.Headers {
|
||
|
req.Header.Add(hKey, hValue)
|
||
|
}
|
||
|
}
|
||
|
|
||
3 years ago
|
// applyParams function additionally configure the http request using params
|
||
3 years ago
|
func (g *HTTPClient) applyParams(p params.Params, req *fasthttp.Request) (err error) {
|
||
3 years ago
|
|
||
|
uri := req.URI()
|
||
|
|
||
|
limit := p.Limit
|
||
|
if limit > 0 {
|
||
|
uri.QueryArgs().Add("limit", strconv.Itoa(limit))
|
||
|
}
|
||
|
|
||
|
page := p.Page
|
||
|
if page > 1 {
|
||
|
uri.QueryArgs().Add("page", strconv.Itoa(page))
|
||
|
}
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
3 years ago
|
// GetPageBySlug returns the only one page using slug filter
|
||
3 years ago
|
func (g *HTTPClient) GetPageBySlug(slug string, queryModifiers ...params.Modifier) (pages *data.Pages, err error) {
|
||
3 years ago
|
|
||
3 years ago
|
pages = &data.Pages{}
|
||
|
defaultParams := params.Params{}
|
||
3 years ago
|
method := fmt.Sprintf(ghostAPIGetPageBySlug, slug)
|
||
|
|
||
3 years ago
|
err = g.doQuery(method, pages, defaultParams)
|
||
3 years ago
|
if err != nil {
|
||
|
pages = nil
|
||
|
}
|
||
|
|
||
3 years ago
|
return
|
||
|
}
|
||
|
|
||
|
// GetPosts returns posts
|
||
3 years ago
|
func (g *HTTPClient) GetPosts(queryModifiers ...params.Modifier) (posts *data.Posts, err error) {
|
||
3 years ago
|
|
||
3 years ago
|
posts = &data.Posts{}
|
||
|
defaultParams := params.Params{}
|
||
|
combinedParams := params.Modifiers(queryModifiers).Apply(defaultParams)
|
||
3 years ago
|
|
||
|
err = g.doQuery(ghostAPIGetPosts, posts, combinedParams)
|
||
3 years ago
|
if err != nil {
|
||
|
posts = nil
|
||
|
}
|
||
|
|
||
3 years ago
|
return
|
||
3 years ago
|
}
|
||
|
|
||
|
// GetPostBySlug returns the only one post using slug filter
|
||
3 years ago
|
func (g *HTTPClient) GetPostBySlug(slug string, queryModifiers ...params.Modifier) (posts *data.Posts, err error) {
|
||
3 years ago
|
|
||
3 years ago
|
posts = &data.Posts{}
|
||
|
defaultParams := params.Params{}
|
||
|
combinedParams := params.Modifiers(queryModifiers).Apply(defaultParams)
|
||
3 years ago
|
method := fmt.Sprintf(ghostAPIGetPostBySlug, slug)
|
||
|
|
||
3 years ago
|
err = g.doQuery(method, posts, combinedParams)
|
||
3 years ago
|
if err != nil {
|
||
|
posts = nil
|
||
|
}
|
||
|
|
||
|
return
|
||
|
}
|