81 lines
3.0 KiB
Go
81 lines
3.0 KiB
Go
package holder
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
"time"
|
|
|
|
meshconditions "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
|
|
keyparts "git.novox.be/novox/mesh-sdk/go/keys"
|
|
"git.novox.be/novox/mesh-sdk/go/views"
|
|
)
|
|
|
|
// FindingKinds are the kinds the driver says (the program) and the transfers say (the tools bundle): each bundle's writer
|
|
// owns its own, since the two share one state `findings` (design 47 G §580, §689).
|
|
var (
|
|
DriverFindingKinds = []string{FindingWindowHeld}
|
|
TransferFindingKinds = []string{"publish-refused", "incoming-full"}
|
|
)
|
|
|
|
// FindingWriter is the module's writer (views.Writer) as the keeper writes and clears through it.
|
|
type FindingWriter interface {
|
|
Write(ctx context.Context, finding meshconditions.Finding) error
|
|
Clear(ctx context.Context, scope, id, kind, why string) error
|
|
}
|
|
|
|
// Findings keeps a bundle's open findings and says them through the module's writer (design 47 G §689, A-14): its `Say` is
|
|
// the Finding callback of the Driver and the Holder; the writer is the held writer (views.HeldWriter), which holds what is open (A-29, A-32).
|
|
type Findings struct {
|
|
Writer FindingWriter
|
|
Logf func(string, ...any)
|
|
Now func() time.Time
|
|
}
|
|
|
|
// Say raises (raised) or clears the finding of a kind about a subject. Its id is the seat's and the subject's, each escaped
|
|
// as a key's name is (design 47 G A-14); the kind stays the bundle's own word.
|
|
func (k *Findings) Say(kind, subject, words string, raised bool) {
|
|
id := keyparts.EscapeName(Self) + "." + keyparts.EscapeName(subject)
|
|
key := views.FindingKey("seat", id, kind)
|
|
if !raised {
|
|
if err := k.Writer.Clear(context.Background(), "seat", id, kind, "it no longer holds"); err != nil {
|
|
k.Logf("the finding %s could not be cleared: %v", key, err)
|
|
}
|
|
return
|
|
}
|
|
at := time.Now()
|
|
if k.Now != nil {
|
|
at = k.Now()
|
|
}
|
|
f := meshconditions.Finding{Scope: "seat", ID: id, Kind: kind, Subject: meshconditions.Subject{Scope: "seat", ID: id},
|
|
Severity: meshconditions.FindingSeverityWarning, Summary: words, Headline: words, Explanation: words,
|
|
Source: kind, Observer: Self, At: at.UTC()}
|
|
if err := k.Writer.Write(context.Background(), f); err != nil {
|
|
k.Logf("the finding %s could not be written: %v", key, err)
|
|
}
|
|
}
|
|
|
|
// DeleteOldFindings deletes, once at a module's start, the findings the keys of an older form hold (design 47 G A-31): the form
|
|
// `seat.<seat>.<kind>_<subject>`, whose kind is no kind the writer owns in its key, so the writer's own first statement does not
|
|
// clear it. Only a key of one of kinds is deleted; the keys of the writer's form (`seat.<seat>.<subject>.<kind>`) are left.
|
|
func DeleteOldFindings(state views.FindingState, seat string, kinds []string) error {
|
|
keys, err := state.Keys()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, k := range keys {
|
|
rest, ok := strings.CutPrefix(k, "seat."+seat+".")
|
|
if !ok {
|
|
continue
|
|
}
|
|
for _, kind := range kinds {
|
|
if strings.HasPrefix(rest, kind+"_") {
|
|
if err := state.Delete(k); err != nil {
|
|
return err
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|