package delivery import "time" // **Whether a module is being delivered on a node, read from its want and its have** (novox/hq ADR 0564 clause 13 and // Limits 12, ADR 0540 ยง7; issue 1952 S7): one derivation, used by the delivery view, which says a module `moving`, // `settled` or `stuck` (the messenger's hold hears those), and by the condition keeper, which holds a module's own // findings while it is delivered there and raises what still stands when the delivery ends. Before, it lived in the view // alone (mesh-delivery-view internal/view motionOf), and a second reader would have judged a delivery its own way. // The motion of a module on a node, as the view says it. const ( MotionMoving = "moving" MotionSettled = "settled" MotionStuck = "stuck" ) // The outcomes of a motion that settled or stuck. const ( // OutcomeRunning is a settled module: the have reached the want, running and healthy. OutcomeRunning = "running" // OutcomeFailed is a have at the wanted fingerprint whose apply or health check failed. OutcomeFailed = "failed" // OutcomeStopped is a module held, or a want the watchman says stopped moving past its bound. OutcomeStopped = "stopped" ) // DefaultDeliveryBound is how long a module's delivery holds its own findings when its manifest names no bound (ADR 0564 // clause 13 (d)): past it, what is held is raised, saying the delivery did not end. const DefaultDeliveryBound = 15 * time.Minute // Motion is where one module's want stands on one node. type Motion struct { // State is MotionMoving, MotionSettled or MotionStuck; empty when there is no want to move to (none, removed, or // naming no fingerprint). State string // Outcome and Words are a settled or stuck motion's: running; failed with the have's words; stopped with the have's // words (held) or the watchman's (stopped moving). Outcome string Words string // Delivering says the module is being delivered there (clause 13 (a)): its want names a fingerprint other than its // have's, or its have's phase is applying. Delivering bool // Failed says the delivery ended failed (Limits 12): the node refused or failed its apply (the have's phase failed, // at whichever fingerprint it kept), or the have at the wanted fingerprint is unhealthy. What a hold kept is raised // at once. Apart from State, which says failed only at the wanted fingerprint, as the view always has. Failed bool } // Ended says the delivery ended, failed or settled healthy at the want: what a hold kept is judged now. func (m Motion) Ended() bool { return m.Failed || (m.State == MotionSettled && !m.Delivering) } // MotionOf is the motion of a module on a node from its want (wanted: one was read), its have (has: one was read) and // the watchman's words when it says the want stopped moving (stuck: it says so and the want has not moved since). func MotionOf(w Want, wanted bool, h Have, has bool, stuckWords string, stuck bool) Motion { if !wanted || w.Removed || w.FP == "" { return Motion{} } m := Motion{Delivering: !has || h.FP != w.FP || h.Phase == PhaseApplying, Failed: has && (h.Phase == PhaseFailed || (h.FP == w.FP && h.Health == HealthFailed))} applied := has && h.FP == w.FP && (h.Composed == "" || h.Composed == w.Composed) switch { case applied && h.Phase == PhaseRunning && h.Health == HealthOK: m.State, m.Outcome = MotionSettled, OutcomeRunning case has && h.Phase == PhaseHeld: m.State, m.Outcome, m.Words = MotionStuck, OutcomeStopped, h.Detail case has && h.FP == w.FP && (h.Health == HealthFailed || h.Phase == PhaseFailed): m.State, m.Outcome, m.Words = MotionStuck, OutcomeFailed, h.Detail case stuck: m.State, m.Outcome, m.Words = MotionStuck, OutcomeStopped, stuckWords default: m.State = MotionMoving } return m }