2023-11-12 19:04:22 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"log"
|
|
|
|
"os"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"deadbeef.codes/steven/ynab-portfolio-monitor/ynab"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
2023-11-13 19:14:19 +00:00
|
|
|
configuredProviders []AccountProvider // Any account providers that are successfully configured get added to this slice
|
2023-11-13 04:40:00 +00:00
|
|
|
ynabClient *ynab.Client // YNAB HTTP client
|
2023-11-12 19:04:22 +00:00
|
|
|
)
|
|
|
|
|
2023-11-13 04:40:00 +00:00
|
|
|
// Called at program startup or if SIGHUP is received
|
2023-11-12 19:04:22 +00:00
|
|
|
func init() {
|
|
|
|
log.Printf("ynab-portfolio-monitor init")
|
|
|
|
|
2023-11-13 04:40:00 +00:00
|
|
|
// Load mandatory application configuration from environment variables
|
2023-11-12 19:04:22 +00:00
|
|
|
envVars := make(map[string]string)
|
|
|
|
envVars["ynab_secret"] = os.Getenv("ynab_secret")
|
|
|
|
envVars["ynab_budget_id"] = os.Getenv("ynab_budget_id")
|
|
|
|
|
|
|
|
// Validate that all required environment variables are set
|
|
|
|
for key, value := range envVars {
|
|
|
|
if value == "" {
|
|
|
|
log.Fatalf("shell environment variable %s is not set", key)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-13 19:14:19 +00:00
|
|
|
// Loop through all account providers and attempt to configure them
|
|
|
|
// if configuration fails, the provider will not be used
|
2023-11-13 04:40:00 +00:00
|
|
|
configuredProviders = make([]AccountProvider, 0)
|
|
|
|
for _, p := range allProviders {
|
|
|
|
err := p.Configure()
|
2023-11-12 19:04:22 +00:00
|
|
|
if err != nil {
|
2023-11-13 04:40:00 +00:00
|
|
|
log.Printf("skipping provider '%s': %v", p.Name(), err)
|
|
|
|
continue
|
2023-11-12 23:50:46 +00:00
|
|
|
}
|
2023-11-13 04:40:00 +00:00
|
|
|
configuredProviders = append(configuredProviders, p)
|
|
|
|
log.Printf("enabled provider '%s'", p.Name())
|
2023-11-12 19:04:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ynab client is static and has no persistent data so is initialized here and not in main program loop
|
2023-11-13 04:40:00 +00:00
|
|
|
var err error
|
2023-11-12 19:04:22 +00:00
|
|
|
ynabClient, err = ynab.NewClient(envVars["ynab_budget_id"], envVars["ynab_secret"])
|
|
|
|
if err != nil {
|
|
|
|
log.Fatalf("failed to create ynab client: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-13 04:40:00 +00:00
|
|
|
// Main program loop
|
2023-11-12 19:04:22 +00:00
|
|
|
func main() {
|
|
|
|
for {
|
2023-11-13 04:40:00 +00:00
|
|
|
// Loop through each configured account provider and attempt to get the account balances, and update YNAB
|
|
|
|
for _, p := range configuredProviders {
|
|
|
|
balances, accountIDs, err := p.GetBalances()
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("failed to get balances with provider '%s': %v", p.Name(), err)
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if len(balances) != len(accountIDs) {
|
2023-11-13 19:14:19 +00:00
|
|
|
log.Printf("'%s' provider data validation error: mismatched balance and accountID slice lengths - expected the same: balances length = %d, accountIDs length = %d", p.Name(), len(balances), len(accountIDs))
|
2023-11-13 04:40:00 +00:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
for i := range balances {
|
|
|
|
err = ynabClient.SetAccountBalance(accountIDs[i], balances[i])
|
|
|
|
if err != nil {
|
|
|
|
log.Printf("failed to update ynab account '%s' balance: %v", accountIDs[i], err)
|
|
|
|
}
|
|
|
|
}
|
2023-11-12 23:50:46 +00:00
|
|
|
}
|
2023-11-12 19:04:22 +00:00
|
|
|
log.Print("Sleeping for 6 hours...")
|
|
|
|
time.Sleep(time.Hour * 6)
|
2023-11-12 23:50:46 +00:00
|
|
|
}
|
2023-11-12 19:04:22 +00:00
|
|
|
}
|