141 lines
6.5 KiB
Go
141 lines
6.5 KiB
Go
package index
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"regexp"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/delivery"
|
|
)
|
|
|
|
// The indexer's doing tool (novox/hq issue 1945; the instruction "tools are how a module is spoken to"): indexer_take_in
|
|
// reads a registered module's manifest now and writes it to the modules state. The tools bundle serves it through the tool
|
|
// runner; the indexer's process serves no request subject (ADR 0437 §4), so the tool writes an ask into the indexer's
|
|
// state takeins, which the indexer watches and answers there, as the builder answers builder_ask_again. The read tools
|
|
// of the indexer's states stay in mesh-delivery-view.
|
|
const (
|
|
TakeInTool = "indexer_take_in"
|
|
// TakeInsState is the indexer's state of take-in asks: the bucket mesh-delivery-indexer_takeins, keyed as the modules state.
|
|
TakeInsState = "takeins"
|
|
TakeInsBucket = delivery.IndexerModule + "_" + TakeInsState
|
|
)
|
|
|
|
// TakeInAsk is a value of the takeins state: which module a person asked to be taken in, why, who and when, and, once the
|
|
// indexer read it, its answer.
|
|
type TakeInAsk struct {
|
|
V int `json:"v"`
|
|
Module string `json:"module,omitempty"`
|
|
// Repository asks the head the gate's source names for a repository to be taken in (TakeInRepository) instead of a module.
|
|
Repository string `json:"repository,omitempty"`
|
|
Why string `json:"why,omitempty"`
|
|
// Judge asks the manifests to be judged again now (indexer_judge_again) instead of the module to be taken in.
|
|
Judge bool `json:"judge,omitempty"`
|
|
// Digest names, with Judge, the one manifest digest of the module to judge (indexer_judge with a digest).
|
|
Digest string `json:"digest,omitempty"`
|
|
// Pending asks the wait under this take-in key to be taken in by hand (indexer_take_in_pending), or with Drop the
|
|
// one pending merge under it to be dropped (indexer_drop_pending), instead of a module (pending.go, ADR 0633 §5).
|
|
Pending string `json:"pending,omitempty"`
|
|
// Merge asks the merge of MergeRepository at this commit to be taken in by hand (indexer_take_in_merge): its merged message
|
|
// is asked of the forge bridge and run through the take-in as a delivered one, under its stream sequence Sequence.
|
|
Merge string `json:"merge,omitempty"`
|
|
MergeRepository string `json:"merge-repository,omitempty"`
|
|
Sequence uint64 `json:"sequence,omitempty"`
|
|
Drop bool `json:"drop,omitempty"`
|
|
By string `json:"by,omitempty"`
|
|
At time.Time `json:"at"`
|
|
Result *TakenIn `json:"result,omitempty"`
|
|
Answered time.Time `json:"answered,omitzero"`
|
|
}
|
|
|
|
// Done says the ask is answered.
|
|
func (a TakeInAsk) Done() bool { return !a.Answered.IsZero() && a.Result != nil }
|
|
|
|
// DecodeTakeIn reads a takeins value.
|
|
func DecodeTakeIn(data []byte) (TakeInAsk, error) {
|
|
var a TakeInAsk
|
|
if err := json.Unmarshal(data, &a); err != nil {
|
|
return a, err
|
|
}
|
|
if a.V != 1 {
|
|
return a, fmt.Errorf("a takeins value of version %d, not 1", a.V)
|
|
}
|
|
if a.Module == "" && a.Repository == "" && a.Pending == "" && a.Merge == "" {
|
|
return a, errors.New("a takeins value naming no module, repository, pending wait or merge")
|
|
}
|
|
return a, nil
|
|
}
|
|
|
|
// NewTakeIn is the value indexer_take_in writes for a module: its key and the value.
|
|
func NewTakeIn(module, why, by string, at time.Time) (string, []byte, error) {
|
|
module = strings.TrimSpace(module)
|
|
if module == "" {
|
|
return "", nil, errors.New("name the module to take in (module)")
|
|
}
|
|
key, err := delivery.ModulesKey(module)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
data, err := json.Marshal(TakeInAsk{V: 1, Module: module, Why: strings.TrimSpace(why), By: by, At: at.UTC()})
|
|
return key, data, err
|
|
}
|
|
|
|
// NewTakeInRepository is the value indexer_take_in writes for a repository: its key and the value.
|
|
func NewTakeInRepository(repository, why, by string, at time.Time) (string, []byte, error) {
|
|
repository = strings.TrimSpace(repository)
|
|
key, err := delivery.RepositoryKey(repository)
|
|
if err != nil {
|
|
return "", nil, err
|
|
}
|
|
data, err := json.Marshal(TakeInAsk{V: 1, Repository: repository, Why: strings.TrimSpace(why), By: by, At: at.UTC()})
|
|
return "repository." + key, data, err
|
|
}
|
|
|
|
// TakeInMergeTool takes one merge in by hand, its merged message asked of the forge bridge (ADR 0633 §5, issue 1585).
|
|
const TakeInMergeTool = "indexer_take_in_merge"
|
|
|
|
var sha40 = regexp.MustCompile(`^[0-9a-f]{40}$`)
|
|
|
|
// NewMergeAsk is the value indexer_take_in_merge writes: its key in takeins, `merge.<commit>`, and the value. sequence is
|
|
// the merge's sequence on the forge bridge's stream, as indexer_heard names it: the pending merge is keyed by it, which
|
|
// keeps the merge order.
|
|
func NewMergeAsk(repository, merge string, sequence uint64, why, by string, at time.Time) (string, []byte, error) {
|
|
repository, merge = strings.TrimSpace(repository), strings.TrimSpace(merge)
|
|
switch {
|
|
case !strings.Contains(repository, "/"):
|
|
return "", nil, errors.New("name the repository as owner/name (repository)")
|
|
case !sha40.MatchString(merge):
|
|
return "", nil, errors.New("name the merge commit, 40 hex digits (merge)")
|
|
case sequence == 0:
|
|
return "", nil, errors.New("name the merge's sequence on the forge bridge's stream (sequence), as indexer_heard names it")
|
|
case strings.TrimSpace(why) == "":
|
|
return "", nil, errors.New("say why (why): a hand act is said in the journal")
|
|
}
|
|
data, err := json.Marshal(TakeInAsk{V: 1, Merge: merge, MergeRepository: repository, Sequence: sequence, Why: strings.TrimSpace(why), By: by, At: at.UTC()})
|
|
return "merge." + merge, data, err
|
|
}
|
|
|
|
// NewPendingAsk is the value indexer_take_in_pending (drop false) or indexer_drop_pending (drop true) writes: its key
|
|
// in takeins, `pending.<take-in|drop>.<key>`, and the value. key is a wait's key as indexer_pending names it, for a
|
|
// drop one pending merge's.
|
|
func NewPendingAsk(key, why, by string, drop bool, at time.Time) (string, []byte, error) {
|
|
key = strings.TrimSpace(key)
|
|
if !strings.HasPrefix(key, "m.") && !(strings.HasPrefix(key, "g.") && !drop) {
|
|
if drop {
|
|
return "", nil, errors.New("name the pending merge to drop by its key, m.<sequence>, as indexer_pending names it")
|
|
}
|
|
return "", nil, errors.New("name the wait to take in by its key, m.<sequence> or g.<group>, as indexer_pending names it")
|
|
}
|
|
if strings.TrimSpace(why) == "" {
|
|
return "", nil, errors.New("say why (why): a hand act on what waits is said in the journal and on its take-in event")
|
|
}
|
|
act := "take-in"
|
|
if drop {
|
|
act = "drop"
|
|
}
|
|
data, err := json.Marshal(TakeInAsk{V: 1, Pending: key, Drop: drop, Why: strings.TrimSpace(why), By: by, At: at.UTC()})
|
|
return "pending." + act + "." + key, data, err
|
|
}
|