Files
mesh-catalog/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/values.go
T

200 lines
6.4 KiB
Go

package main
import (
"encoding/json"
"reflect"
"time"
mdc "git.novox.be/novox/mesh-delivery/contracts/go/clients/meshdeliveryclient"
seat "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdelivery"
)
// The holders the gate reads or hears, by the names their modules go by (the gate's own constants, one per reader: the
// manifest's reads and consumes name them).
const (
tellerModule = "mesh-delivery-teller"
viewModule = "mesh-delivery-view"
forgeBridgeModule = "mesh-delivery-forge-bridge"
)
// The values the gate keeps in the seat mesh-delivery's states. The seat's types are the layout and meshdeliveryclient
// holds their rules and codecs; Source, Owed and Answer are used as they are, and the three whose seat form differs from the
// form the gate works in (a pull request that holds its head, the router's ask as bytes, a turn's times as plain times)
// are converted at the edge, so a stored value decodes unchanged (novox/hq ADR 0634 §2).
type (
// Source is the state source's value.
Source = seat.SourceByMainValue
// Owed is the state owed's value: what the forge bridge performs.
Owed = seat.OwedByRepositoryNumberHeadActValue
// Answer is the operator's answer as the gate acts on it.
Answer = mdc.Answer
)
// Merge is the state merges' value: a group's merge.
type Merge struct {
V int
Group string
Ask string
Approved map[string]string
Pulls []MergePull
}
// MergePull is one pull request of a merge: its expected head, its state, the merge commit once merged, the forge's words
// when refused.
type MergePull struct {
mdc.Head
State mdc.MergeState
Commit string
Words string
}
func (m Merge) stored() seat.MergesByGroupValue {
out := seat.MergesByGroupValue{Approved: m.Approved, Ask: m.Ask, Group: m.Group, V: int64(m.V)}
if m.Pulls != nil {
out.Pulls = make([]seat.MergesByGroupValuePullsItem, len(m.Pulls))
}
for i, p := range m.Pulls {
out.Pulls[i] = seat.MergesByGroupValuePullsItem{Commit: p.Commit, Head: p.Head.Head, Number: int64(p.Number),
Repository: p.Repository, State: string(p.State), Words: p.Words}
}
return out
}
func mergeFromSeat(s seat.MergesByGroupValue) Merge {
out := Merge{V: int(s.V), Group: s.Group, Ask: s.Ask, Approved: s.Approved}
for _, p := range s.Pulls {
out.Pulls = append(out.Pulls, MergePull{Head: mdc.Head{Repository: p.Repository, Number: int(p.Number), Head: p.Head},
State: mdc.MergeState(p.State), Commit: p.Commit, Words: p.Words})
}
return out
}
// EncodeMerge is m as the value of a merges key.
func EncodeMerge(m Merge) ([]byte, error) { return mdc.EncodeMerge(m.stored()) }
// DecodeMerge reads the value of a merges key.
func DecodeMerge(data []byte) (Merge, error) {
s, err := mdc.DecodeMerge(data)
if err != nil {
return Merge{}, err
}
return mergeFromSeat(s), nil
}
// SameMerge says whether two merges are the same value.
func SameMerge(a, b Merge) bool { return mdc.SameMerge(a.stored(), b.stored()) }
// Ask is the state asks' value: the router's ask for a group's merge at its heads.
type Ask struct {
V int
Group string
Heads []mdc.Head
Ask json.RawMessage
// Asking counts the times the gate wrote this group's ask at these heads (0 or 1 for the first).
Asking int
}
func (a Ask) stored() seat.AsksByMergeGroupHeadsValue {
out := seat.AsksByMergeGroupHeadsValue{Asking: int64(a.Asking), Group: a.Group, V: int64(a.V)}
if len(a.Ask) > 0 {
out.Ask = a.Ask
}
if a.Heads != nil {
out.Heads = make([]seat.AsksByMergeGroupHeadsValueHeadsItem, len(a.Heads))
}
for i, h := range a.Heads {
out.Heads[i] = seat.AsksByMergeGroupHeadsValueHeadsItem{Head: h.Head, Number: int64(h.Number), Repository: h.Repository}
}
return out
}
func askFromSeat(s seat.AsksByMergeGroupHeadsValue) (Ask, error) {
raw, err := json.Marshal(s.Ask)
if err != nil {
return Ask{}, err
}
return Ask{V: int(s.V), Group: s.Group, Heads: mdc.HeadsOf(s.Heads), Ask: raw, Asking: int(s.Asking)}, nil
}
// EncodeAsk is a as the value of an asks key.
func EncodeAsk(a Ask) ([]byte, error) { return mdc.EncodeAsk(a.stored()) }
// DecodeAsk reads the value of an asks key.
func DecodeAsk(data []byte) (Ask, error) {
s, err := mdc.DecodeAsk(data)
if err != nil {
return Ask{}, err
}
return askFromSeat(s)
}
// SameAsk says whether two asks are the same value, the router's ask by its content.
func SameAsk(a, b Ask) bool {
var x, y any
if json.Unmarshal(a.Ask, &x) != nil || json.Unmarshal(b.Ask, &y) != nil {
return false
}
a.Ask, b.Ask = nil, nil
return reflect.DeepEqual(a, b) && reflect.DeepEqual(x, y)
}
// Turn is the state turns' value: the approved deliveries waiting to merge in one repository, in the order of the Approve.
type Turn struct {
V int
Repository string
Waiting []TurnWait
}
// TurnWait is one approved delivery in a turn; WaitsFor, WaitsSince and Step say the check of another delivery it waits on.
type TurnWait struct {
Group string
Heads string
Ask string
Approved time.Time
Since time.Time
WaitsFor string
WaitsSince time.Time
Step string
}
func (t Turn) stored() seat.TurnsByRepositoryValue {
out := seat.TurnsByRepositoryValue{Repository: t.Repository, V: int64(t.V), Waiting: []seat.TurnsByRepositoryValueWaitingItem{}}
for _, w := range t.Waiting {
item := seat.TurnsByRepositoryValueWaitingItem{Approved: w.Approved, Ask: w.Ask, Group: w.Group, Heads: w.Heads,
Since: w.Since, Step: w.Step, WaitsFor: w.WaitsFor}
if !w.WaitsSince.IsZero() {
since := w.WaitsSince
item.WaitsSince = &since
}
out.Waiting = append(out.Waiting, item)
}
return out
}
func turnFromSeat(s seat.TurnsByRepositoryValue) Turn {
out := Turn{V: int(s.V), Repository: s.Repository}
for _, w := range s.Waiting {
item := TurnWait{Group: w.Group, Heads: w.Heads, Ask: w.Ask, Approved: w.Approved, Since: w.Since, WaitsFor: w.WaitsFor, Step: w.Step}
if w.WaitsSince != nil {
item.WaitsSince = *w.WaitsSince
}
out.Waiting = append(out.Waiting, item)
}
return out
}
// EncodeTurn is t as the value of a turns key.
func EncodeTurn(t Turn) ([]byte, error) { return mdc.EncodeTurn(t.stored()) }
// DecodeTurn reads the value of a turns key.
func DecodeTurn(data []byte) (Turn, error) {
s, err := mdc.DecodeTurn(data)
if err != nil {
return Turn{}, err
}
return turnFromSeat(s), nil
}
// SameTurn says whether two turns are the same value.
func SameTurn(a, b Turn) bool { return mdc.SameTurn(a.stored(), b.stored()) }