ynab-portfolio-monitor/providers/staticjsonFinnhub/providerImpl.go

101 lines
2.6 KiB
Go

package staticjsonFinnhub
import (
"encoding/json"
"errors"
"fmt"
"io"
"os"
)
type security struct {
Symbol string `json:"symbol"`
Quantity int `json:"quantity"`
}
type account struct {
YnabAccountID string `json:"ynabAccountId"`
Securities []security `json:"securities"`
}
type inputData struct {
Accounts []account `json:"accounts"`
}
type Provider struct {
data *inputData // Data stored on disk and loaded when program starts
client *client // HTTP client for interacting with Finnhub API
}
func (p *Provider) Name() string {
return "Static JSON - Finnhub"
}
// Configures the provider for usage via environment variables and inputData
// If an error is returned, the provider will not be used
func (p *Provider) Configure() error {
var err error
// Load input data from disk
p.data, err = loadInputData()
if err != nil {
return err
}
b, _ := json.Marshal(p.data)
fmt.Println(string(b))
apiKey := os.Getenv("staticjson_finnhub_key")
if apiKey == "" {
return fmt.Errorf("this account provider is not configured: missing staticjson_finnhub_key environment variable")
}
p.client, err = newClient(apiKey)
if err != nil {
return fmt.Errorf("failed to create new client: %v", err)
}
return nil
}
// Returns slices of account balances and mapped YNAB account IDs, along with an error
func (p *Provider) GetBalances() ([]int, []string, error) {
balances := make([]int, 0)
ynabAccountIDs := make([]string, 0)
for i := range p.data.Accounts {
balance := 0
for j := range p.data.Accounts[i].Securities {
price, err := p.client.getQuote(p.data.Accounts[i].Securities[j].Symbol)
if err != nil {
return balances, ynabAccountIDs, fmt.Errorf("failed to get quote for security with symbol '%s': %v", p.data.Accounts[i].Securities[j].Symbol, err)
}
balance += price * p.data.Accounts[i].Securities[j].Quantity
}
balances = append(balances, balance)
ynabAccountIDs = append(ynabAccountIDs, p.data.Accounts[i].YnabAccountID)
}
return balances, ynabAccountIDs, nil
}
// Load input data from disk
func loadInputData() (*inputData, error) {
data := &inputData{}
f, err := os.Open("data/staticjsonFinnhub-data.json")
if errors.Is(err, os.ErrNotExist) {
return nil, fmt.Errorf("this account provider is not configured: missing data/staticjsonFinnhub-data.json")
}
defer f.Close()
b, err := io.ReadAll(f)
if err != nil {
return nil, fmt.Errorf("failed to read file data/staticjsonFinnhub-data.json: %v", err)
}
err = json.Unmarshal(b, data)
if err != nil {
return nil, fmt.Errorf("failed to unmarshal data/staticjsonFinnhub-data.json to inputData struct: %v", err)
}
return data, nil
}