200 lines
6.4 KiB
Go
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()) }
|