Skip to content

Commit

Permalink
refactor(maven): cache response body from Maven registries
Browse files Browse the repository at this point in the history
  • Loading branch information
cuixq committed Nov 19, 2024
1 parent c20dd9f commit dbc8c03
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 46 deletions.
84 changes: 46 additions & 38 deletions internal/resolution/datasource/maven_registry.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package datasource

import (
"bytes"
"context"
"encoding/xml"
"errors"
Expand Down Expand Up @@ -30,8 +31,12 @@ type MavenRegistryAPIClient struct {
// Cache fields
mu *sync.Mutex
cacheTimestamp *time.Time // If set, this means we loaded from a cache
projects *RequestCache[string, maven.Project]
metadata *RequestCache[string, maven.Metadata]
responses *RequestCache[string, response]
}

type response struct {
StatusCode int
Body []byte
}

func NewMavenRegistryAPIClient(registry string) (*MavenRegistryAPIClient, error) {
Expand All @@ -44,8 +49,7 @@ func NewMavenRegistryAPIClient(registry string) (*MavenRegistryAPIClient, error)
return &MavenRegistryAPIClient{
defaultRegistry: registry,
mu: &sync.Mutex{},
projects: NewRequestCache[string, maven.Project](),
metadata: NewRequestCache[string, maven.Metadata](),
responses: NewRequestCache[string, response](),
}, nil
}

Expand All @@ -55,12 +59,11 @@ func (m *MavenRegistryAPIClient) WithoutRegistries() *MavenRegistryAPIClient {
defaultRegistry: m.defaultRegistry,
mu: m.mu,
cacheTimestamp: m.cacheTimestamp,
projects: m.projects,
metadata: m.metadata,
responses: m.responses,
}
}

// Add adds the given registry to the list of registries if it has not been added.
// AddRegistry adds the given registry to the list of registries if it has not been added.
func (m *MavenRegistryAPIClient) AddRegistry(registry string) error {
if slices.Contains(m.registries, registry) {
return nil
Expand Down Expand Up @@ -147,14 +150,12 @@ func (m *MavenRegistryAPIClient) getProject(ctx context.Context, registry, group
return maven.Project{}, fmt.Errorf("failed to join path: %w", err)
}

return m.projects.Get(u, func() (maven.Project, error) {
var proj maven.Project
if err := get(ctx, u, &proj); err != nil {
return maven.Project{}, err
}
var project maven.Project
if err := m.get(ctx, u, &project); err != nil {
return maven.Project{}, err
}

return proj, nil
})
return project, nil
}

// getVersionMetadata fetches a version level maven-metadata.xml and parses it to maven.Metadata.
Expand All @@ -164,14 +165,12 @@ func (m *MavenRegistryAPIClient) getVersionMetadata(ctx context.Context, registr
return maven.Metadata{}, fmt.Errorf("failed to join path: %w", err)
}

return m.metadata.Get(u, func() (maven.Metadata, error) {
var metadata maven.Metadata
if err := get(ctx, u, &metadata); err != nil {
return maven.Metadata{}, err
}
var metadata maven.Metadata
if err := m.get(ctx, u, &metadata); err != nil {
return maven.Metadata{}, err
}

return metadata, nil
})
return metadata, nil
}

// GetArtifactMetadata fetches an artifact level maven-metadata.xml and parses it to maven.Metadata.
Expand All @@ -181,33 +180,42 @@ func (m *MavenRegistryAPIClient) getArtifactMetadata(ctx context.Context, regist
return maven.Metadata{}, fmt.Errorf("failed to join path: %w", err)
}

return m.metadata.Get(u, func() (maven.Metadata, error) {
var metadata maven.Metadata
if err := get(ctx, u, &metadata); err != nil {
return maven.Metadata{}, err
}
var metadata maven.Metadata
if err := m.get(ctx, u, &metadata); err != nil {
return maven.Metadata{}, err
}

return metadata, nil
})
return metadata, nil
}

func get(ctx context.Context, url string, dst interface{}) error {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return fmt.Errorf("failed to make new request: %w", err)
}
func (m *MavenRegistryAPIClient) get(ctx context.Context, url string, dst interface{}) error {
resp, err := m.responses.Get(url, func() (response, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil)
if err != nil {
return response{}, fmt.Errorf("failed to make new request: %w", err)
}

resp, err := http.DefaultClient.Do(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return response{}, fmt.Errorf("%w: Maven registry query failed: %w", errAPIFailed, err)
}
defer resp.Body.Close()

if b, err := io.ReadAll(resp.Body); err == nil {
return response{StatusCode: resp.StatusCode, Body: b}, nil
}

return response{}, fmt.Errorf("failed to read body: %w", err)
})
if err != nil {
return fmt.Errorf("%w: Maven registry query failed: %w", errAPIFailed, err)
return err
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
return fmt.Errorf("%w: Maven registry query status: %s", errAPIFailed, resp.Status)
return fmt.Errorf("%w: Maven registry query status: %d", errAPIFailed, resp.StatusCode)
}

return NewMavenDecoder(resp.Body).Decode(dst)
return NewMavenDecoder(bytes.NewReader(resp.Body)).Decode(dst)
}

// NewMavenDecoder returns an xml decoder with CharsetReader and Entity set.
Expand Down
11 changes: 3 additions & 8 deletions internal/resolution/datasource/maven_registry_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,11 @@ package datasource

import (
"time"

"deps.dev/util/maven"
)

type mavenRegistryCache struct {
Timestamp *time.Time
Projects map[string]maven.Project // url -> project
Metadata map[string]maven.Metadata // url -> metadata
Responses map[string]response // url -> response
}

func (m *MavenRegistryAPIClient) GobEncode() ([]byte, error) {
Expand All @@ -23,8 +20,7 @@ func (m *MavenRegistryAPIClient) GobEncode() ([]byte, error) {

cache := mavenRegistryCache{
Timestamp: m.cacheTimestamp,
Projects: m.projects.GetMap(),
Metadata: m.metadata.GetMap(),
Responses: m.responses.GetMap(),
}

return gobMarshal(&cache)
Expand All @@ -45,8 +41,7 @@ func (m *MavenRegistryAPIClient) GobDecode(b []byte) error {
defer m.mu.Unlock()

m.cacheTimestamp = cache.Timestamp
m.projects.SetMap(cache.Projects)
m.metadata.SetMap(cache.Metadata)
m.responses.SetMap(cache.Responses)

return nil
}

0 comments on commit dbc8c03

Please sign in to comment.