79 lines
2.9 KiB
Go
79 lines
2.9 KiB
Go
package main
|
|
|
|
// The delivery line (novox/hq ADR 0505 §1): every message about a problem — a condition or a module's notice,
|
|
// raised, asked, reopened, escalated or reminded — ends, after its since-when line, with whether a delivery was
|
|
// running on what it is about:
|
|
//
|
|
// - "During the delivery of <modules> to <machines>." when an open walk touches its subject;
|
|
// - "<n> after the delivery of <modules> to <machines>, which <outcome>." when a walk that touched it ended within
|
|
// its settle (a delivered walk settling, a failed or stopped one in the two minutes after it, §6);
|
|
// - "No delivery running." otherwise.
|
|
//
|
|
// The line is this router's, from the walks it keeps (ADR 0308 §1); no producer adds it. It names modules and
|
|
// machines as the operator says them, never an id, and is judged by the content rule with the rest of the body.
|
|
|
|
import (
|
|
"sort"
|
|
"time"
|
|
)
|
|
|
|
// NoDeliveryLine is the delivery line of a message no walk touches.
|
|
const NoDeliveryLine = "No delivery running."
|
|
|
|
// outcomeWords are a walk's outcome as the delivery line says it.
|
|
var outcomeWords = map[string]string{WalkDelivered: "succeeded", WalkFailed: "failed", WalkStopped: "was stopped"}
|
|
|
|
// carriesDeliveryLine says whether a message of a record says the delivery line: a problem's message, and not its
|
|
// clearing, its silencing, a plain notice or an ask's own message.
|
|
func carriesDeliveryLine(r *Record, what string) bool {
|
|
switch what {
|
|
case "cleared", "silenced", "tell":
|
|
return false
|
|
}
|
|
return r.Origin != "ask"
|
|
}
|
|
|
|
// deliveryLine is the line for a record's message at a moment.
|
|
func (h *Holder) deliveryLine(r *Record, now time.Time) string {
|
|
s := subjectOf(r)
|
|
h.mu.Lock()
|
|
defer h.mu.Unlock()
|
|
h.init()
|
|
var during, after []*Walk
|
|
for _, w := range h.walks {
|
|
if !w.touches(s) {
|
|
continue
|
|
}
|
|
switch {
|
|
case w.settling() && now.Before(w.SettleUntil) && !now.Before(w.Ended):
|
|
after = append(after, w)
|
|
case !w.settling():
|
|
during = append(during, w) // open, within its bound or past it (ADR 0505 §7)
|
|
}
|
|
}
|
|
if len(during) > 0 {
|
|
sort.Slice(during, func(i, j int) bool { return during[i].Started.Before(during[j].Started) })
|
|
return plainly("During the delivery of "+deliveryWords(during[0].Touches)+".", "During a delivery.")
|
|
}
|
|
if f := h.failedJustNow(s, now); f != nil {
|
|
after = append(after, f)
|
|
}
|
|
if len(after) == 0 {
|
|
return NoDeliveryLine
|
|
}
|
|
sort.Slice(after, func(i, j int) bool { return after[i].Ended.After(after[j].Ended) })
|
|
w := after[0]
|
|
ago := roughly(now.Sub(w.Ended))
|
|
return plainly(ago+" after the delivery of "+deliveryWords(w.Touches)+", which "+outcomeWords[w.Outcome]+".",
|
|
ago+" after a delivery, which "+outcomeWords[w.Outcome]+".")
|
|
}
|
|
|
|
// plainly is a line when the content rule lets it leave the mesh, else the same said without the names that it
|
|
// refused, so the line never withholds the message it ends.
|
|
func plainly(line, without string) string {
|
|
if _, ok := Check(line); ok {
|
|
return line
|
|
}
|
|
return without
|
|
}
|