82 lines
3.4 KiB
Go
82 lines
3.4 KiB
Go
// Package ends is the teller's recovery tool teller_end_ask and the value it writes (issue 774; the instruction "tools are
|
|
// how a module is spoken to"). An ask the teller holds open at the router keeps one of the three places the router gives
|
|
// its asker (asks.MostOpen) until it is answered, it lapses, or the gate or the assigner takes its key away. When that last
|
|
// never comes (on 2026-10-31 two merge asks of pull requests merged by another path held two places for a day, and a
|
|
// assignments ask was refused for want of room), a person ends the ask by hand. The teller's process serves no request
|
|
// subject (ADR 0437 §4), so the tool writes an end into the teller's state ends, which the teller watches, carries out
|
|
// and answers there, as the indexer answers indexer_take_in.
|
|
package ends
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliveryclient"
|
|
)
|
|
|
|
const (
|
|
// module is the teller's own name (its manifest's module), the holder of the bucket.
|
|
module = "mesh-delivery-teller"
|
|
Tool = "teller_end_ask"
|
|
// State is the teller's state of ends asked by hand: the bucket mesh-delivery-teller_ends.
|
|
State = "ends"
|
|
Bucket = module + "_" + State
|
|
)
|
|
|
|
// Result is the teller's answer to an end: which ask it found (its router id and the gate's or the assigner's key it was
|
|
// asked for), whether this end ended it, and what it did in words.
|
|
type Result struct {
|
|
ID string `json:"id,omitempty"`
|
|
Key string `json:"key,omitempty"`
|
|
Ended bool `json:"ended"`
|
|
Says string `json:"says"`
|
|
}
|
|
|
|
// End is a value of the state ends: the ask named (a router id, as operator-channel's asks show it, or the key of the
|
|
// gate's or the assigner's asks it was asked for), why, who and when, and, once the teller carried it out, its answer.
|
|
type End struct {
|
|
V int `json:"v"`
|
|
Ask string `json:"ask"`
|
|
Why string `json:"why"`
|
|
By string `json:"by,omitempty"`
|
|
At time.Time `json:"at"`
|
|
Result *Result `json:"result,omitempty"`
|
|
Answered time.Time `json:"answered,omitzero"`
|
|
}
|
|
|
|
// Done says the end is answered.
|
|
func (e End) Done() bool { return !e.Answered.IsZero() && e.Result != nil }
|
|
|
|
// Decode reads a value of the state ends.
|
|
func Decode(data []byte) (End, error) {
|
|
var e End
|
|
if err := json.Unmarshal(data, &e); err != nil {
|
|
return e, err
|
|
}
|
|
if e.V != 1 {
|
|
return e, fmt.Errorf("an ends value of version %d, not 1", e.V)
|
|
}
|
|
if e.Ask == "" || e.Why == "" {
|
|
return e, errors.New("an ends value naming no ask or no why")
|
|
}
|
|
return e, nil
|
|
}
|
|
|
|
// New is the value teller_end_ask writes: its key and the value. The key is the router's spelling of the name given
|
|
// (meshdeliveryclient.AskID), which a bucket key takes whatever the name holds, and is the same for the same name, so a second end
|
|
// of one ask overwrites the first.
|
|
func New(ask, why, by string, at time.Time) (string, []byte, error) {
|
|
ask, why = strings.TrimSpace(ask), strings.TrimSpace(why)
|
|
if ask == "" {
|
|
return "", nil, errors.New("name the ask to end (ask): its router id, as operator-channel's asks show it, or the key of the gate's or the assigner's asks")
|
|
}
|
|
if why == "" {
|
|
return "", nil, errors.New("say why the ask is ended (why), in plain words: it is logged with who ended it")
|
|
}
|
|
data, err := json.Marshal(End{V: 1, Ask: ask, Why: why, By: by, At: at.UTC()})
|
|
return meshdeliveryclient.AskID(ask), data, err
|
|
}
|