this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 87 lines 2.1 kB view raw
1package data 2 3import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "io" 8 "log/slog" 9 "net/http" 10 "sync" 11 "time" 12 13 "github.com/eagleusb/proxycon/internal/types" 14 "github.com/eagleusb/proxycon/internal/utility" 15) 16 17const ( 18 datasourceURL = "https://europe-west1-bitstack-test.cloudfunctions.net/coding-challenge-v2" 19) 20 21type BitcoinPrices struct { 22 mu sync.RWMutex 23 prices []types.Price 24 client *http.Client 25} 26 27// NewBitcoinPrices return a bitcoin prices http loader. 28func NewBitcoinPrices() *BitcoinPrices { 29 return &BitcoinPrices{ 30 client: &http.Client{ 31 Timeout: 60 * time.Second, 32 Transport: utility.NewLoggingRoundTripper(&http.Transport{ 33 MaxIdleConns: 10, 34 MaxIdleConnsPerHost: 10, 35 IdleConnTimeout: 300 * time.Second, 36 }), 37 }, 38 } 39} 40 41// SetPrices set the prices from upstream and store them safely (mutex lock). 42func (f *BitcoinPrices) SetPrices(ctx context.Context) error { 43 prices, err := f.fetchPrices(ctx) 44 if err != nil { 45 return err 46 } 47 48 f.mu.Lock() 49 f.prices = prices 50 f.mu.Unlock() 51 52 slog.Info("loaded bitcoin prices from datasource", "count", len(prices)) 53 return nil 54} 55 56// GetPrices get the bitcoin prices from memory. 57func (f *BitcoinPrices) GetPrices() []types.Price { 58 f.mu.RLock() 59 defer f.mu.RUnlock() 60 return f.prices 61} 62 63// fetchPrices implement the upstream fetch of bitcoin prices. 64func (f *BitcoinPrices) fetchPrices(ctx context.Context) ([]types.Price, error) { 65 req, err := http.NewRequestWithContext(ctx, http.MethodGet, datasourceURL, nil) 66 if err != nil { 67 return nil, fmt.Errorf("create request: %w", err) 68 } 69 70 resp, err := f.client.Do(req) 71 if err != nil { 72 return nil, fmt.Errorf("fetch datasource: %w", err) 73 } 74 defer resp.Body.Close() 75 76 if resp.StatusCode != http.StatusOK { 77 body, _ := io.ReadAll(io.LimitReader(resp.Body, 1024)) 78 return nil, fmt.Errorf("datasource returned %d: %s", resp.StatusCode, string(body)) 79 } 80 81 var datasourceResp types.DatasourceResponse 82 if err := json.NewDecoder(resp.Body).Decode(&datasourceResp); err != nil { 83 return nil, fmt.Errorf("decode datasource response: %w", err) 84 } 85 86 return datasourceResp.Data, nil 87}