Serve a ledger owner its repairs rebuild, reindex, snapshot and lag as tools, its own ledgers only, marked acts or reads (issue 1966 T4)
This commit is contained in:
@@ -0,0 +1,146 @@
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/buscalls"
|
||||
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
||||
|
||||
"github.com/novox/mesh-tools/node-tools/internal/bus"
|
||||
"github.com/novox/mesh-tools/node-tools/internal/launch"
|
||||
"github.com/novox/mesh-tools/node-tools/internal/ledger"
|
||||
)
|
||||
|
||||
// A module's ledgers as the tool runner serves them (novox/hq ADR 0597, design 25 § 12.4, § 12.5; issue 1966): opened
|
||||
// for the module whose bundle or whose repair tool asks, from its own bindings alone, with its types and the connection
|
||||
// its history is published on.
|
||||
|
||||
// LedgerTypes is where the runner reads a ledger's types, by module and local name. Where it reads them from on the
|
||||
// live mesh is not decided (issue 1966: the binding carries no types, and no record names a source); until it is,
|
||||
// the runner refuses to open a ledger and says why, and a test gives the types.
|
||||
type LedgerTypes func(module, local string) ([]catalogue.LedgerType, error)
|
||||
|
||||
// errTypesUndecided is the refusal of a ledger whose types the runner has no source for.
|
||||
func errTypesUndecided(module, local string) error {
|
||||
return fmt.Errorf("the tool runner cannot open %s's ledger %q: it reads a ledger's types from nowhere yet, since its "+
|
||||
"binding carries none and no record names their source (issue 1966)", module, local)
|
||||
}
|
||||
|
||||
// ledgerSource is how the runner opens a module's ledger: its types, and the connection its history and snapshots are
|
||||
// published on (the module's ledger credential, ADR 0597 §9).
|
||||
type ledgerSource struct {
|
||||
types LedgerTypes
|
||||
writer func(module string) (*bus.Conn, error)
|
||||
}
|
||||
|
||||
// ledger opens one of a module's ledgers by its local name.
|
||||
func (c *consumers) ledger(module, local string) (*ledger.Ledger, error) {
|
||||
b, err := c.conn.Binding(module, local, catalogue.StorageLedger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
types := c.ledgers.types
|
||||
if types == nil {
|
||||
return nil, errTypesUndecided(module, local)
|
||||
}
|
||||
ts, err := types(module, local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var writer *bus.Conn
|
||||
if c.ledgers.writer != nil {
|
||||
if writer, err = c.ledgers.writer(module); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
history, state, snapshots := c.conn.LedgerStores(b, writer)
|
||||
return &ledger.Ledger{Module: module, Name: local, Types: ts, History: history, State: state, Snapshots: snapshots,
|
||||
Indexes: c.conn.LedgerIndexes(b), Logf: c.logf}, nil
|
||||
}
|
||||
|
||||
// hasLedger is whether a module's membership binds a ledger.
|
||||
func hasLedger(conn *bus.Conn, module string) bool {
|
||||
for _, b := range conn.Bindings(module) {
|
||||
if b.Storage == catalogue.StorageLedger {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// The repair tools the runner serves for every module owning a ledger (design 25 § 12.5), named so no bundle's tool is
|
||||
// taken for one.
|
||||
const (
|
||||
RepairRebuild = "ledger_rebuild"
|
||||
RepairReindex = "ledger_reindex"
|
||||
RepairSnapshot = "ledger_snapshot"
|
||||
RepairLag = "ledger_lag"
|
||||
)
|
||||
|
||||
// The effects a tool carries (novox/hq ADR 0387 §1).
|
||||
const (
|
||||
EffectReads = "reads"
|
||||
EffectActs = "acts"
|
||||
)
|
||||
|
||||
// repairTools are a module's ledger repairs as tools, each limited to its own ledgers: the request's ledger is a local
|
||||
// name of the module whose tool is called.
|
||||
func (c *consumers) repairTools(module string) []launch.Tool {
|
||||
schema := func(props string, required ...string) json.RawMessage {
|
||||
req, _ := json.Marshal(append([]string{"ledger"}, required...))
|
||||
return json.RawMessage(`{"type":"object","properties":{"ledger":{"type":"string","description":"the ledger's local name"}` +
|
||||
props + `},"required":` + string(req) + `}`)
|
||||
}
|
||||
instance := `,"instance":{"type":"string","description":"one instance, such as decision/0290; every instance when empty"}`
|
||||
run := func(do func(l *ledger.Ledger, args json.RawMessage) (any, error)) func(string, json.RawMessage) (json.RawMessage, error) {
|
||||
return func(_ string, args json.RawMessage) (json.RawMessage, error) {
|
||||
var named struct {
|
||||
Ledger string `json:"ledger"`
|
||||
}
|
||||
if err := json.Unmarshal(args, &named); err != nil || named.Ledger == "" {
|
||||
return nil, errors.New("a repair names the ledger, by its local name")
|
||||
}
|
||||
l, err := c.ledger(module, named.Ledger)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
answer, err := do(l, args)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return json.Marshal(answer)
|
||||
}
|
||||
}
|
||||
return []launch.Tool{
|
||||
{Name: RepairRebuild, Effect: EffectActs, Input: schema(instance + `,"from":{"type":"string","enum":["history","snapshot"],"description":"derive from the whole history (the default) or from the snapshot and the operations after it"}`),
|
||||
Description: "Derive a ledger instance's state again from its history or its snapshot, and write it and its snapshot (novox/hq ADR 0597 §10).",
|
||||
Run: run(func(l *ledger.Ledger, args json.RawMessage) (any, error) {
|
||||
var r buscalls.RebuildRequest
|
||||
_ = json.Unmarshal(args, &r)
|
||||
return l.Rebuild(r)
|
||||
})},
|
||||
{Name: RepairReindex, Effect: EffectActs, Input: schema(`,"index":{"type":"string","description":"the declared index"}`, "index"),
|
||||
Description: "Build a ledger's declared index again from its states, derived from its history (novox/hq ADR 0597 §4, §10).",
|
||||
Run: run(func(l *ledger.Ledger, args json.RawMessage) (any, error) {
|
||||
var r buscalls.ReindexRequest
|
||||
_ = json.Unmarshal(args, &r)
|
||||
return l.Reindex(r)
|
||||
})},
|
||||
{Name: RepairSnapshot, Effect: EffectActs, Input: schema(instance),
|
||||
Description: "Rewrite the snapshot of a ledger instance that is behind its state (novox/hq ADR 0597 §8, §10).",
|
||||
Run: run(func(l *ledger.Ledger, args json.RawMessage) (any, error) {
|
||||
var r buscalls.InstanceRequest
|
||||
_ = json.Unmarshal(args, &r)
|
||||
return l.Snapshot(r)
|
||||
})},
|
||||
{Name: RepairLag, Effect: EffectReads, Input: schema(""),
|
||||
Description: "Say every ledger instance whose state or snapshot is behind its history, and each declared index behind it (novox/hq ADR 0597 §10).",
|
||||
Run: run(func(l *ledger.Ledger, args json.RawMessage) (any, error) {
|
||||
var r buscalls.LedgerRequest
|
||||
_ = json.Unmarshal(args, &r)
|
||||
return l.Lag(r)
|
||||
})},
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user