summaryrefslogtreecommitdiff
path: root/cache.go
diff options
context:
space:
mode:
authorBen Burwell <ben@benburwell.com>2020-06-06 22:13:59 -0400
committerBen Burwell <ben@benburwell.com>2020-06-06 22:13:59 -0400
commit38db545ba808c69dd911a6bf45c2a340d3ae3487 (patch)
tree4c4bf2b2c15c48736c245a371cf75f0abe7e0b20 /cache.go
parentb242fa87a86ee27ed0fccf925d49e13b9fe607ef (diff)
Redirect to git.burwell.ioHEAD0.2.0master
Diffstat (limited to 'cache.go')
-rw-r--r--cache.go129
1 files changed, 0 insertions, 129 deletions
diff --git a/cache.go b/cache.go
deleted file mode 100644
index d43fa77..0000000
--- a/cache.go
+++ /dev/null
@@ -1,129 +0,0 @@
-package main
-
-import (
- "context"
- "log"
- "path"
- "sync"
- "time"
-)
-
-// A PackageCache holds information about Go packages and their upstream
-// repositories.
-//
-// Given a package name, it looks for a similarly named repository in one of
-// the upstream hosts and holds on to the result for quicker subsequent access.
-type PackageCache struct {
- // ExpireAfter is how long to consider a found repository valid for. As
- // repositories do not frequently move around, this could be rather long,
- // though it also determines how long a user might have to wait for a new
- // repository to become available if they previously got a 404.
- ExpireAfter time.Duration
-
- // UpstreamTimeout is how long we should allow HTTP requests to upstream
- // hosts to carry on before they are canceled.
- UpstreamTimeout time.Duration
-
- // Hosts are the RepoHosts which should be checked for a repository matching
- // the package name. Hosts are checked in order; if two hosts both have a
- // repo with the desired name, the repo host which is listed first will
- // "win".
- Hosts []RepoHost
-
- // Logger is a logger for diagnostics
- Logger *log.Logger
-
- // CanonicalPrefix is the package prefix to use when naming packages. E.g.,
- // when looking for a package named "conf", we'll treat the package name as
- // CanonicalPrefix + "/conf", e.g. burwell.io/conf.
- CanonicalPrefix string
-
- entries sync.Map // concurrency-safe map[string]entry
-}
-
-type entry struct {
- t time.Time
- pkg *Package
-}
-
-// A Package represents a Go package's canonical name and its source git
-// repository.
-type Package struct {
- Name string
- Repo string
-}
-
-// Get loads package name from the cache, consulting upstream repositories to
-// find a matching repo if not present. As this method is meant to be called in
-// the critical path of an incoming HTTP request, it can also be cancelled with
-// the supplied context.
-func (c *PackageCache) Get(ctx context.Context, name string) (Package, bool) {
- val, ok := c.entries.Load(name)
- if !ok {
- return c.load(ctx, name)
- }
- ent := val.(entry)
-
- if time.Now().After(ent.t.Add(c.ExpireAfter)) {
- return c.load(ctx, name)
- }
-
- if ent.pkg == nil {
- return Package{}, false
- }
-
- return *ent.pkg, true
-}
-
-// load looks for a package in the upstream repos, and if found, stores it in
-// the cache. If no matching repo is found, a nil entry is stored in the map so
-// we don't immediately re-check the upstreams for subsequent requests.
-func (c *PackageCache) load(ctx context.Context, name string) (Package, bool) {
- pkg, ok := c.find(ctx, name)
- if !ok {
- c.entries.Store(name, entry{t: time.Now()})
- return Package{}, false
- }
- c.entries.Store(name, entry{t: time.Now(), pkg: &pkg})
- return pkg, true
-}
-
-// requestContext creates a context for making HTTP requests to upstream hosts.
-func (c *PackageCache) requestContext(ctx context.Context) (context.Context, context.CancelFunc) {
- if c.UpstreamTimeout == 0 {
- return ctx, func() {}
- }
- return context.WithTimeout(ctx, c.UpstreamTimeout)
-}
-
-// logf logs a message using the configured logger, if any.
-func (c *PackageCache) logf(msg string, args ...interface{}) {
- if c.Logger == nil {
- return
- }
- c.Logger.Printf(msg, args...)
-}
-
-// find consults the configured upstream hosts to try to find a matching repo
-// for package name.
-func (c *PackageCache) find(ctx context.Context, name string) (Package, bool) {
- c.logf("loading %s", name)
- for _, h := range c.Hosts {
- reqCtx, cancel := c.requestContext(ctx)
- defer cancel()
- repo, ok, err := h.HostsRepo(reqCtx, name)
- if err != nil {
- c.logf("error checking upstream for repo %s: %v", name, err)
- return Package{}, false
- }
- if ok {
- c.logf("found repo %s: %s", name, repo)
- return Package{
- Name: path.Join(c.CanonicalPrefix, name),
- Repo: repo,
- }, true
- }
- }
- c.logf("could not find repo %s on any host", name)
- return Package{}, false
-}