package teller import ( "context" "crypto/tls" _ "embed" "encoding/json" "fmt" "io" "log" "net/http" "strings" "time" "gogs.inhome.blapointe.com/ana-ledger/src/bank" "golang.org/x/time/rate" ) type Client struct { cert tls.Certificate } var _ bank.Agg = Client{} var ( //go:embed certificate.pem certificate []byte //go:embed private_key.pem privateKey []byte //go:embed token.txt Tokens string ) func New() (Client, error) { cert, err := tls.X509KeyPair(certificate, privateKey) return Client{cert: cert}, err } func (c Client) Accounts(ctx context.Context) ([]bank.Account, error) { var result []bank.Account for _, token := range strings.Fields(Tokens) { var more []bank.Account if err := c.get(ctx, "https://api.teller.io/accounts", token, &more); err != nil { return nil, err } for i := range more { more[i].Token = token } result = append(result, more...) } return result, nil } func (c Client) Transactions(ctx context.Context, a bank.Account) ([]bank.Transaction, error) { var result []bank.Transaction err := c.get(ctx, "https://api.teller.io/accounts/"+a.Account+"/transactions", a.Token, &result) return result, err } var limiter = rate.NewLimiter(0.1, 1) func (c Client) get(ctx context.Context, url, token string, ptr interface{}) error { if err := limiter.Wait(ctx); err != nil { return err } log.Printf("Teller.Get(%s, %s)", url, token) httpc := &http.Client{ Timeout: time.Second, Transport: &http.Transport{ DisableKeepAlives: true, TLSClientConfig: &tls.Config{Certificates: []tls.Certificate{c.cert}}, }, } req, err := http.NewRequest(http.MethodGet, url, nil) if err != nil { return err } req.SetBasicAuth(token, "") req = req.WithContext(ctx) resp, err := httpc.Do(req) if err != nil { return err } defer resp.Body.Close() b, _ := io.ReadAll(resp.Body) if err := json.Unmarshal(b, &ptr); err != nil { return fmt.Errorf("cannot unmarshal: %w: %s", err, b) } return nil }