engine

package
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 20, 2026 License: AGPL-3.0 Imports: 20 Imported by: 0

Documentation

Overview

Package engine runs syncs (source → history) and pushes (history → destinations), on demand and on a schedule.

Index

Constants

View Source
const AdjustSetting = "fundarr.adjust"

AdjustSetting, in a source's settings, turns balance corrections off ("off").

View Source
const Hold = 48 * time.Hour

Hold is how long a balance correction waits before going to destinations: a platform's history sometimes catches up a sync or two later.

Variables

View Source
var ErrBusy = errors.New("already running")
View Source
var ErrDelivered = errors.New("this correction was already sent to a destination: remove it there first, then forget its delivery")
View Source
var ErrNoImport = errors.New("this source cannot import statements")
View Source
var ErrNotInteractive = errors.New("this source does not sign in")
View Source
var LoginPoll = 2 * time.Second

LoginPoll is how often a waiting sign-in is checked.

Functions

func NeedsLogin added in v0.2.0

func NeedsLogin(ent *store.Entity) bool

NeedsLogin reports whether a sync of the source failed for want of a sign-in (and waits for the user).

Types

type Engine

type Engine struct {
	Store *store.Store
	Box   *secret.Box
	HTTP  *http.Client
	Log   *slog.Logger
	// Prices values assets (corrections, rewards, transfers); nil leaves
	// them without a price.
	Prices *price.Service
	// Now is replaceable in tests.
	Now func() time.Time
	// OnChange, when set, is called after the history may have changed
	// (a sync, an import, a correction rewritten). It must not block.
	OnChange func()
	// contains filtered or unexported fields
}

func New

func New(st *store.Store, box *secret.Box, log *slog.Logger) *Engine

func (*Engine) Adjust

func (e *Engine) Adjust(ctx context.Context, ent *store.Entity) (gaps []model.Gap, changed bool, err error)

Adjust brings a source's corrections in line with its gaps: corrections not delivered anywhere yet are recomputed from scratch; delivered ones stay and are corrected by new ones if they turn out wrong. Returns the gaps that existed before correcting.

func (*Engine) AnswerLogin added in v0.2.0

func (e *Engine) AnswerLogin(ctx context.Context, id, code string) (*Login, error)

AnswerLogin sends the code the sign-in asks for.

func (*Engine) Build

func (e *Engine) Build(ent *store.Entity) (source.Source, error)

Build instantiates the connector of a configured source.

func (*Engine) BuildDest

func (e *Engine) BuildDest(ent *store.Entity) (dest.Destination, error)

BuildDest instantiates a configured destination.

func (*Engine) CancelLogin added in v0.2.0

func (e *Engine) CancelLogin(id string)

CancelLogin forgets a sign-in.

func (*Engine) Costs

func (e *Engine) Costs(ctx context.Context, l *Ledger, ccy string) map[string]decimal.Decimal

Costs is what each incoming asset cost, in ccy (see model.Costs). Without a price service, only what was bought with ccy itself is known.

func (*Engine) Currency

func (e *Engine) Currency(ctx context.Context) string

Currency returns the currency values are shown in (Settings, default EUR).

func (*Engine) DeleteManual

func (e *Engine) DeleteManual(ctx context.Context, sourceID, activityID string) error

DeleteManual removes an activity the user entered; the balance check corrects again whatever it explained.

func (*Engine) Import

func (e *Engine) Import(ctx context.Context, id, name string, data []byte) (*ImportResult, error)

Import reads a statement exported from the platform and makes it the history of the period it covers.

func (*Engine) Ledger

func (e *Engine) Ledger(ctx context.Context) (*Ledger, error)

func (*Engine) LoginNeeded added in v0.2.0

func (e *Engine) LoginNeeded(ent *store.Entity) bool

LoginNeeded reports whether syncing the source needs a sign-in first.

func (*Engine) LoginState added in v0.2.0

func (e *Engine) LoginState(id string) *Login

LoginState returns the source's sign-in, if one was started.

func (*Engine) Push

func (e *Engine) Push(ctx context.Context, destID string) (*PushResult, error)

Push delivers everything not yet delivered to a destination, route by route.

func (*Engine) Readjust

func (e *Engine) Readjust(ctx context.Context, id string) error

Readjust recomputes a source's corrections now (after a settings change).

func (*Engine) Reclassify

func (e *Engine) Reclassify(ctx context.Context, sourceID, activityID string, r Reclassify) (*model.Activity, error)

func (*Engine) Reconcile

func (e *Engine) Reconcile(ctx context.Context, sourceID string) ([]model.Gap, error)

Reconcile compares a source's replayed history with its last balances.

func (*Engine) Resync

func (e *Engine) Resync(ctx context.Context, id string) (*SyncResult, error)

Resync fetches the whole history again, as on the first run (after a connector learned new kinds of activity). Known activities are deduplicated.

func (*Engine) Run

func (e *Engine) Run(ctx context.Context)

Run syncs enabled sources whose interval has elapsed, every minute, until ctx is done. Retries failed pushes once an hour.

func (*Engine) Running

func (e *Engine) Running(id string) bool

Running reports whether a sync or push is in progress for this id.

func (*Engine) Seal

func (e *Engine) Seal(secrets map[string]string) ([]byte, error)

Seal encrypts the secret fields of a settings map.

func (*Engine) Secrets

func (e *Engine) Secrets(ent *store.Entity) (map[string]string, error)

Secrets returns the decrypted secrets alone (to keep them when a form is saved without retyping them).

func (*Engine) Session added in v0.2.0

func (e *Engine) Session(ent *store.Entity) *source.Session

Session is what a source says of its sign-in (nil when it has none).

func (*Engine) StartLogin added in v0.2.0

func (e *Engine) StartLogin(ctx context.Context, id, method string) (*Login, error)

StartLogin starts a sign-in (method "" takes the source's first). One already waiting is returned as is: a second notification is never sent while the first can still be approved.

func (*Engine) Sync

func (e *Engine) Sync(ctx context.Context, id string) (*SyncResult, error)

Sync fetches a source's history and balances, then pushes to its routes.

func (*Engine) Test

func (e *Engine) Test(ctx context.Context, ent *store.Entity) error

Test checks a source's credentials without syncing.

func (*Engine) Tolerance

func (e *Engine) Tolerance() decimal.Decimal

Tolerance is the relative difference ignored when reconciling (rounding of displayed balances).

func (*Engine) Transfers

func (e *Engine) Transfers(ctx context.Context, acts []model.Activity) ([]model.Pair, error)

Transfers pairs withdrawals and deposits across every source.

func (*Engine) UnitPrice

func (e *Engine) UnitPrice(ctx context.Context, ccy string) func(model.Asset, time.Time) (decimal.Decimal, bool)

UnitPrice prices one unit of an asset on the day of at, in ccy. Without a price service, only ccy itself is known.

func (*Engine) Values

func (e *Engine) Values(ent *store.Entity) (map[string]string, error)

Values merges an entity's settings with its decrypted secrets.

type ImportResult

type ImportResult struct {
	From       time.Time   `json:"from"`
	To         time.Time   `json:"to"`
	Activities int         `json:"activities"`
	Replaced   int         `json:"replaced"`
	Notes      []string    `json:"notes"`
	Gaps       []model.Gap `json:"gaps"`
}

ImportResult summarizes a statement import.

type Ledger

type Ledger struct {
	Acts  []model.Activity
	Pairs []model.Pair
	// In maps a deposit to its withdrawal, Out a withdrawal to its deposit.
	In, Out map[string]string
	ByID    map[string]model.Activity
}

Ledger is everything that crosses sources, computed together.

type Login added in v0.2.0

type Login struct {
	Method    string            `json:"method"`
	Challenge *source.Challenge `json:"challenge,omitempty"`
	Started   time.Time         `json:"started"`
	Done      bool              `json:"done,omitempty"`
	Error     string            `json:"error,omitempty"`
}

Login is where a sign-in stands, for the UI.

type PushResult

type PushResult struct {
	Counts map[dest.Status]int `json:"counts"`
}

PushResult summarizes one push.

type Reclassify

type Reclassify struct {
	As    string       `json:"as"` // "reward", "deposit", "withdrawal", "buy", "sell", "fee"
	Time  time.Time    `json:"time"`
	Quote model.Amount `json:"quote"` // buy and sell: what was paid or received
	Note  string       `json:"note"`
}

Reclassify replaces a balance correction with what really happened, told by the user: a reward, a transfer from another wallet of theirs, a purchase (or a sale) for some amount of another asset.

type SyncResult

type SyncResult struct {
	Fetched int `json:"fetched"`
	New     int `json:"new"`
	// Adjusted: assets whose history did not add up and got a correction.
	Adjusted int `json:"adjusted"`
	// Gaps left unexplained (corrections turned off for the source).
	Gaps []model.Gap `json:"gaps"`
}

SyncResult summarizes one sync.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL