136 lines
4.8 KiB
Go
136 lines
4.8 KiB
Go
package runtime
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"sort"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/buscalls"
|
|
)
|
|
|
|
// The capabilities the tool runner states of the calls it answers (novox/hq ADR 0595 §9, ADR 0597; design 25 § 12.4): each is
|
|
// a family of the methods a bundle asks it, named so a manifest's `capabilities` can ask for it, and stated in its announcement
|
|
// (announce.Capabilities) for its machine's node-engine to take into the node's record. A module whose manifest asks for one is
|
|
// held off a machine whose runner does not state it.
|
|
const (
|
|
CapBusStateCalls = "bus-state-calls"
|
|
CapLedgerCalls = "ledger-calls"
|
|
)
|
|
|
|
// callFamilies are the methods each capability stands for, the ones BusState and BusStateWatch answer.
|
|
var callFamilies = map[string][]string{
|
|
CapBusStateCalls: {buscalls.ObjectsPut, buscalls.ObjectsGet, buscalls.ObjectsList, buscalls.ObjectsDelete, buscalls.ObjectsInfo,
|
|
buscalls.ObjectsWatch, buscalls.StreamRead, buscalls.StreamFill, buscalls.WorkQueueSize, buscalls.WorkQueueDead},
|
|
CapLedgerCalls: {buscalls.LedgerApply, buscalls.LedgerGet, buscalls.LedgerHistory, buscalls.LedgerWatch, buscalls.LedgerQuery,
|
|
buscalls.LedgerRebuild, buscalls.LedgerReindex, buscalls.LedgerSnapshot, buscalls.LedgerLag},
|
|
}
|
|
|
|
// CallCapabilities is every capability of the calls this runner answers, sorted.
|
|
func CallCapabilities() []string {
|
|
out := make([]string, 0, len(callFamilies))
|
|
for c := range callFamilies {
|
|
out = append(out, c)
|
|
}
|
|
sort.Strings(out)
|
|
return out
|
|
}
|
|
|
|
// BusState answers a bundle's calls on its module's bus state in the new form (mesh-sdk buscalls; novox/hq ADR 0595
|
|
// §9, design 25 § 12.5; issue 1966): each as the module whose bundle asks, never a module the request names, so a
|
|
// bundle reaches its own module's bindings alone.
|
|
func (b *moduleBus) BusState(method string, params json.RawMessage) (json.RawMessage, error) {
|
|
conn := b.all.conn
|
|
var answer any
|
|
var err error
|
|
switch method {
|
|
case buscalls.ObjectsPut:
|
|
var r buscalls.ObjectsPutRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
answer, err = conn.ObjectsPut(b.module, r)
|
|
}
|
|
case buscalls.ObjectsGet:
|
|
var r buscalls.ObjectsNameRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
var got *buscalls.ObjectData
|
|
if got, err = conn.ObjectsGet(b.module, r); err == nil && got == nil {
|
|
return json.RawMessage("null"), nil
|
|
}
|
|
answer = got
|
|
}
|
|
case buscalls.ObjectsDelete:
|
|
var r buscalls.ObjectsNameRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
err = conn.ObjectsDelete(b.module, r)
|
|
answer = buscalls.Done{}
|
|
}
|
|
case buscalls.ObjectsList:
|
|
var r buscalls.ObjectsRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
answer, err = conn.ObjectsList(b.module, r)
|
|
}
|
|
case buscalls.ObjectsInfo:
|
|
var r buscalls.ObjectsRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
answer, err = conn.ObjectsInfo(b.module, r)
|
|
}
|
|
case buscalls.StreamRead:
|
|
var r buscalls.StreamReadRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
answer, err = conn.StreamRead(b.module, r)
|
|
}
|
|
case buscalls.StreamFill:
|
|
var r buscalls.StreamRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
answer, err = conn.StreamFill(b.module, r)
|
|
}
|
|
case buscalls.WorkQueueSize:
|
|
var r buscalls.WorkQueueRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
answer, err = conn.WorkQueueSize(b.module, r)
|
|
}
|
|
case buscalls.WorkQueueDead:
|
|
var r buscalls.WorkQueueDeadRequest
|
|
if err = decode(method, params, &r); err == nil {
|
|
answer, err = conn.WorkQueueDead(b.module, r)
|
|
}
|
|
case buscalls.LedgerApply, buscalls.LedgerGet, buscalls.LedgerHistory, buscalls.LedgerQuery, buscalls.LedgerRebuild,
|
|
buscalls.LedgerReindex, buscalls.LedgerSnapshot, buscalls.LedgerLag:
|
|
answer, err = b.ledgerCall(method, params)
|
|
default:
|
|
return nil, fmt.Errorf("the runtime answers no %s", method)
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return json.Marshal(answer)
|
|
}
|
|
|
|
// BusStateWatch hands a bundle each change of its objects or its ledger, the current ones first.
|
|
func (b *moduleBus) BusStateWatch(method string, params json.RawMessage, deliver func(json.RawMessage) error) (func(), error) {
|
|
switch method {
|
|
case buscalls.ObjectsWatch:
|
|
var r buscalls.ObjectsWatchRequest
|
|
if err := decode(method, params, &r); err != nil {
|
|
return nil, err
|
|
}
|
|
return b.all.conn.ObjectsWatch(b.module, r, func(change buscalls.ObjectsChange) error {
|
|
raw, err := json.Marshal(change)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return deliver(raw)
|
|
})
|
|
case buscalls.LedgerWatch:
|
|
return b.ledgerWatch(params, deliver)
|
|
}
|
|
return nil, fmt.Errorf("the runtime answers no %s", method)
|
|
}
|
|
|
|
// decode reads a bus-state call's request.
|
|
func decode(method string, params json.RawMessage, into any) error {
|
|
if err := json.Unmarshal(params, into); err != nil {
|
|
return fmt.Errorf("%s's request is not of its shape (mesh-sdk buscalls): %w", method, err)
|
|
}
|
|
return nil
|
|
}
|