♻️ Refactored client HTTP repository
This commit is contained in:
parent
e552351bd5
commit
10cc589dc6
|
@ -0,0 +1,111 @@
|
|||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/tomnomnom/linkheader"
|
||||
http "github.com/valyala/fasthttp"
|
||||
"source.toby3d.me/website/oauth/internal/client"
|
||||
"source.toby3d.me/website/oauth/internal/model"
|
||||
"willnorris.com/go/microformats"
|
||||
)
|
||||
|
||||
type httpClientRepository struct {
|
||||
client *http.Client
|
||||
}
|
||||
|
||||
func NewHTTPClientRepository(c *http.Client) client.Repository {
|
||||
return &httpClientRepository{
|
||||
client: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (repo *httpClientRepository) Get(ctx context.Context, id string) (*model.Client, error) {
|
||||
req := http.AcquireRequest()
|
||||
defer http.ReleaseRequest(req)
|
||||
|
||||
req.Header.SetMethod(http.MethodGet)
|
||||
req.SetRequestURI(id)
|
||||
|
||||
resp := http.AcquireResponse()
|
||||
defer http.ReleaseResponse(resp)
|
||||
|
||||
if err := repo.client.Do(req, resp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
client := new(model.Client)
|
||||
client.ID = model.URL(id)
|
||||
client.RedirectURI = make([]model.URL, 0)
|
||||
|
||||
for _, l := range linkheader.Parse(string(resp.Header.Peek(http.HeaderLink))) {
|
||||
if !strings.Contains(l.Rel, "redirect_uri") {
|
||||
continue
|
||||
}
|
||||
|
||||
client.RedirectURI = append(client.RedirectURI, model.URL(l.URL))
|
||||
}
|
||||
|
||||
u, err := url.Parse(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := microformats.Parse(bytes.NewReader(resp.Body()), u)
|
||||
|
||||
populateItems(client, data.Items)
|
||||
populateRels(client, data.Rels)
|
||||
|
||||
return client, nil
|
||||
}
|
||||
|
||||
func populateItems(c *model.Client, items []*microformats.Microformat) {
|
||||
for _, item := range items {
|
||||
if len(item.Type) == 0 && item.Type[0] != "h-app" && item.Type[0] != "h-x-app" {
|
||||
continue
|
||||
}
|
||||
|
||||
for key, property := range item.Properties {
|
||||
if len(property) == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
switch key {
|
||||
case "name":
|
||||
for i := range property {
|
||||
val, _ := property[i].(string)
|
||||
c.Name = model.URL(val)
|
||||
}
|
||||
case "logo":
|
||||
for i := range property {
|
||||
switch val := property[i].(type) {
|
||||
case string:
|
||||
c.Logo = model.URL(val)
|
||||
case map[string]string:
|
||||
c.Logo = model.URL(val["value"])
|
||||
}
|
||||
}
|
||||
case "url":
|
||||
for i := range property {
|
||||
val, _ := property[i].(string)
|
||||
c.URL = model.URL(val)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func populateRels(c *model.Client, rels map[string][]string) {
|
||||
for key, values := range rels {
|
||||
if key != "redirect_uri" {
|
||||
continue
|
||||
}
|
||||
|
||||
for i := range values {
|
||||
c.RedirectURI = append(c.RedirectURI, model.URL(values[i]))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package http_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/valyala/fasthttp"
|
||||
"source.toby3d.me/website/oauth/internal/client/repository/http"
|
||||
"source.toby3d.me/website/oauth/internal/common"
|
||||
"source.toby3d.me/website/oauth/internal/model"
|
||||
)
|
||||
|
||||
const testBody string = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Example App</title>
|
||||
<link rel="redirect_uri" href="/redirect">
|
||||
</head>
|
||||
<body>
|
||||
<div class="h-app">
|
||||
<img src="/logo.png" class="u-logo">
|
||||
<a href="/" class="u-url p-name">Example App</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
|
||||
func TestGet(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
//nolint: exhaustivestruct
|
||||
srv := &fasthttp.Server{
|
||||
ReduceMemoryUsage: true,
|
||||
GetOnly: true,
|
||||
CloseOnShutdown: true,
|
||||
Handler: func(ctx *fasthttp.RequestCtx) {
|
||||
ctx.SuccessString(common.MIMETextHTML, testBody)
|
||||
ctx.Response.Header.Set(fasthttp.HeaderLink, `<https://app.example.com/redirect>; rel="redirect_uri">`)
|
||||
},
|
||||
}
|
||||
|
||||
go func(srv *fasthttp.Server) {
|
||||
assert.NoError(t, srv.ListenAndServe("127.0.0.1:2368"))
|
||||
}(srv)
|
||||
|
||||
t.Cleanup(func() {
|
||||
assert.NoError(t, srv.Shutdown())
|
||||
})
|
||||
|
||||
result, err := http.NewHTTPClientRepository(new(fasthttp.Client)).Get(context.TODO(), "http://127.0.0.1:2368/")
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, &model.Client{
|
||||
ID: "http://127.0.0.1:2368/",
|
||||
Name: "Example App",
|
||||
Logo: "http://127.0.0.1:2368/logo.png",
|
||||
URL: "http://127.0.0.1:2368/",
|
||||
RedirectURI: []model.URL{
|
||||
"https://app.example.com/redirect",
|
||||
"http://127.0.0.1:2368/redirect",
|
||||
},
|
||||
}, result)
|
||||
}
|
|
@ -1,11 +1,16 @@
|
|||
package model
|
||||
|
||||
type Client struct {
|
||||
ID string
|
||||
URL string
|
||||
Name string
|
||||
Logo string
|
||||
RedirectURI []string
|
||||
ID URL
|
||||
Name URL
|
||||
Logo URL
|
||||
URL URL
|
||||
RedirectURI []URL
|
||||
}
|
||||
|
||||
func (Client) Bucket() []byte { return []byte("clients") }
|
||||
func NewClient() *Client {
|
||||
c := new(Client)
|
||||
c.RedirectURI = make([]URL, 0)
|
||||
|
||||
return c
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue