diff --git a/internal/source/gitlab/api/lookup.go b/internal/source/gitlab/api/lookup.go index 73a3ce433a65e3930ac6061973412aa832feb9e4..28208d5a3b9b6457b942f941bb0cbdb2e9d80ff2 100644 --- a/internal/source/gitlab/api/lookup.go +++ b/internal/source/gitlab/api/lookup.go @@ -2,6 +2,7 @@ package api // Lookup defines an API lookup action with a response that GitLab sends type Lookup struct { + ETag string Name string Error error Domain *VirtualDomain diff --git a/internal/source/gitlab/client/client.go b/internal/source/gitlab/client/client.go index afe9da6f8a06205378bc6d629bc322d13adaa009..97be3e7468607fba9767182187c2130529f2e7c7 100644 --- a/internal/source/gitlab/client/client.go +++ b/internal/source/gitlab/client/client.go @@ -2,6 +2,8 @@ package client import ( "context" + "crypto/md5" + "encoding/hex" "encoding/json" "errors" "fmt" @@ -88,6 +90,12 @@ func (gc *Client) GetLookup(ctx context.Context, host string) api.Lookup { lookup := api.Lookup{Name: host} lookup.Error = json.NewDecoder(resp.Body).Decode(&lookup.Domain) + sum := md5.New() + io.Copy(sum, resp.Body) + io.WriteString(sum, host) + hash := sum.Sum(nil) + lookup.ETag = hex.EncodeToString(hash[:]) + return lookup } diff --git a/internal/source/gitlab/client/client_stub.go b/internal/source/gitlab/client/client_stub.go index 604f127bdab135714e4ea83f4ed3699a1b43751d..38dc1518c4397ffe1f4dcb99bfc6431f1cab2fcb 100644 --- a/internal/source/gitlab/client/client_stub.go +++ b/internal/source/gitlab/client/client_stub.go @@ -31,6 +31,7 @@ func (c StubClient) GetLookup(ctx context.Context, host string) api.Lookup { } defer f.Close() + lookup.ETag = "simple-etag" lookup.Error = json.NewDecoder(f).Decode(&lookup.Domain) return lookup diff --git a/internal/source/gitlab/gitlab.go b/internal/source/gitlab/gitlab.go index cce707339592c0797d2076b2d5a88c22fab7b878..f9cf297ebe50c7343c3649cf23eb10739598529b 100644 --- a/internal/source/gitlab/gitlab.go +++ b/internal/source/gitlab/gitlab.go @@ -6,6 +6,9 @@ import ( "net/http" "path" "strings" + "time" + + store "github.com/patrickmn/go-cache" "gitlab.com/gitlab-org/gitlab-pages/internal/domain" "gitlab.com/gitlab-org/gitlab-pages/internal/request" @@ -19,6 +22,7 @@ import ( // information about domains from GitLab instance. type Gitlab struct { client api.Resolver + store *store.Cache } // New returns a new instance of gitlab domain source. @@ -28,7 +32,16 @@ func New(config client.Config) (*Gitlab, error) { return nil, err } - return &Gitlab{client: cache.NewCache(client)}, nil + return NewFromClient(client), nil +} + +// NewFromClient fabricates a new Gitlab domains source using api.Client passed +// in an argument +func NewFromClient(client api.Client) *Gitlab { + return &Gitlab{ + client: cache.NewCache(client), + store: store.New(time.Hour, time.Minute), + } } // GetDomain return a representation of a domain that we have fetched from @@ -45,6 +58,15 @@ func (g *Gitlab) GetDomain(name string) (*domain.Domain, error) { return nil, nil } + if len(lookup.ETag) == 0 { + return nil, errors.New("lookup does not contain etag") + } + + entry, ok := g.store.Get(lookup.ETag) + if ok { + return entry.(*domain.Domain), nil + } + domain := domain.Domain{ Name: name, CertificateCert: lookup.Domain.Certificate, @@ -52,6 +74,8 @@ func (g *Gitlab) GetDomain(name string) (*domain.Domain, error) { Resolver: g, } + g.store.SetDefault(lookup.ETag, &domain) + return &domain, nil } diff --git a/internal/source/gitlab/gitlab_test.go b/internal/source/gitlab/gitlab_test.go index 0e855f10b2723ecc7962ee4ad80c3d3ce0a6b23b..ab852e50b9546962a3603ca5655e77bc05c3dd3c 100644 --- a/internal/source/gitlab/gitlab_test.go +++ b/internal/source/gitlab/gitlab_test.go @@ -10,9 +10,9 @@ import ( ) func TestGetDomain(t *testing.T) { - t.Run("when the response if correct", func(t *testing.T) { + t.Run("when the response is correct", func(t *testing.T) { client := client.StubClient{File: "client/testdata/test.gitlab.io.json"} - source := Gitlab{client: client} + source := NewFromClient(client) domain, err := source.GetDomain("test.gitlab.io") require.NoError(t, err) @@ -22,7 +22,7 @@ func TestGetDomain(t *testing.T) { t.Run("when the response is not valid", func(t *testing.T) { client := client.StubClient{File: "/dev/null"} - source := Gitlab{client: client} + source := NewFromClient(client) domain, err := source.GetDomain("test.gitlab.io") @@ -33,7 +33,7 @@ func TestGetDomain(t *testing.T) { func TestResolve(t *testing.T) { client := client.StubClient{File: "client/testdata/test.gitlab.io.json"} - source := Gitlab{client: client} + source := NewFromClient(client) t.Run("when requesting nested group project with root path", func(t *testing.T) { target := "https://test.gitlab.io:443/my/pages/project/"