summaryrefslogtreecommitdiff
path: root/internal/api/cache.go
blob: 5c682f414049d8429168bad2d9526d5c998e7b1a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
package api

import (
	"context"
	"net/http"
	"sync"
	"time"

	"codeberg.org/eduVPN/eduvpn-common/internal/api/endpoints"
)

// EndpointCache is a struct that caches well-known API endpoints
type EndpointCache struct {
	lastUpdate map[string]time.Time
	lastEP     map[string]*endpoints.Endpoints
	mu         sync.Mutex
}

// Get returns a cached or fresh endpoint cache copy
func (ec *EndpointCache) Get(ctx context.Context, wk string, transport http.RoundTripper) (*endpoints.Endpoints, error) {
	ec.mu.Lock()
	defer ec.mu.Unlock()

	// get the last update time
	lu := time.Time{}
	if v, ok := ec.lastUpdate[wk]; ok {
		lu = v
	}

	// if not 10 minutes have passed, return cached copy
	if !lu.IsZero() && !time.Now().After(lu.Add(10*time.Minute)) {
		v, ok := ec.lastEP[wk]
		if ok {
			return v, nil
		}
	}

	// get fresh API endpoints
	ep, err := getEndpoints(ctx, wk, transport)
	if err != nil {
		return nil, err
	}

	// update endpoints
	ec.lastUpdate[wk] = time.Now()
	ec.lastEP[wk] = ep

	return ep, nil
}

var (
	epCache     *EndpointCache
	epCacheOnce sync.Once
)

// GetEndpointCache returns the global singleton endpoint cache
// or creates one if it does not exist
func GetEndpointCache() *EndpointCache {
	epCacheOnce.Do(func() {
		epCache = &EndpointCache{
			lastUpdate: make(map[string]time.Time),
			lastEP:     make(map[string]*endpoints.Endpoints),
		}
	})

	return epCache
}