From a5d3480e7e5d4fdbaecc66658417560789025ca8 Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 20 Oct 2026 21:54:25 +0200 Subject: [PATCH] Let messages-per-hour 0 turn the hourly pause off (issue 1476) --- .../cmd/messenger/cap_setting_test.go | 27 +++++++++++++++++-- modules/messenger/cmd/messenger/holder.go | 6 ++--- modules/messenger/cmd/messenger/main.go | 19 +++++++++---- modules/messenger/cmd/messenger/outbox.go | 3 ++- modules/messenger/module.json | 4 +-- 5 files changed, 46 insertions(+), 13 deletions(-) diff --git a/modules/messenger/cmd/messenger/cap_setting_test.go b/modules/messenger/cmd/messenger/cap_setting_test.go index 58b9ae10..c6c2fdf2 100644 --- a/modules/messenger/cmd/messenger/cap_setting_test.go +++ b/modules/messenger/cmd/messenger/cap_setting_test.go @@ -34,10 +34,33 @@ func TestMessagesPerHourIsReadFromTheSettingsFile(t *testing.T) { } return readSettings(p) } - if s, err := read(`{"messages-per-hour": 100}`); err != nil || s.MessagesPerHour != 100 { + if s, err := read(`{"messages-per-hour": 100}`); err != nil || s.MessagesPerHour == nil || *s.MessagesPerHour != 100 { t.Fatalf("set: %+v %v", s, err) } - if s, err := read(`{"time-zone": ""}`); err != nil || s.MessagesPerHour != 0 { + if s, err := read(`{"messages-per-hour": 0}`); err != nil || s.MessagesPerHour == nil || *s.MessagesPerHour != 0 { + t.Fatalf("zero: %+v %v", s, err) + } + if s, err := read(`{"time-zone": ""}`); err != nil || s.MessagesPerHour != nil { t.Fatalf("unset: %+v %v", s, err) } } + +// 0 turns the pause off (issue 1476): every message goes out and the pause is never said. +func TestACapOfZeroTurnsThePauseOff(t *testing.T) { + h, tg, _, c, _ := newHolder(t) + h.Desk = nil + h.CapPerHour = func() int { return 0 } + for i := 0; i < 500; i++ { + h.Condition(EventRaised, cond(fmt.Sprintf("machine.m%d.silent", i), Urgent, "a machine is silent")) + c.pass(BurstWindow + time.Second) + h.Flush() + } + if len(tg.sends) != 500 { + t.Fatalf("sent %d of 500", len(tg.sends)) + } + for _, m := range tg.sends { + if strings.HasPrefix(m.Title, "Mesh messages paused") { + t.Fatalf("the pause was said with the cap off") + } + } +} diff --git a/modules/messenger/cmd/messenger/holder.go b/modules/messenger/cmd/messenger/holder.go index d8fb7f8a..b203c24a 100644 --- a/modules/messenger/cmd/messenger/holder.go +++ b/modules/messenger/cmd/messenger/holder.go @@ -325,7 +325,7 @@ type Holder struct { // `only-what-needs-me`, ADR 0308 §4); nil, none is. NeedsOnly func(kind string) bool // CapPerHour is the most messages one channel gets an hour (the setting messages-per-hour, issue 1476); - // nil, or a value below one, is DefaultCapPerHour. TellCapPerHour is its own and stays fixed. + // nil, or a value below zero, is DefaultCapPerHour; 0 is no cap at all. TellCapPerHour is its own and stays fixed. CapPerHour func() int work sync.Mutex // one event, call or tick at a time @@ -1212,10 +1212,10 @@ func withheldLine(line string, refusal Refusal, passes func(string) (Refusal, bo return "(a line carrying " + refusal.What + " is withheld here)" } -// capPerHour is the cap now in force on a channel's messages an hour. +// capPerHour is the cap now in force on a channel's messages an hour; 0 is none. func (h *Holder) capPerHour() int { if h.CapPerHour != nil { - if n := h.CapPerHour(); n >= 1 { + if n := h.CapPerHour(); n >= 0 { return n } } diff --git a/modules/messenger/cmd/messenger/main.go b/modules/messenger/cmd/messenger/main.go index 24be3b0f..5fbfa29b 100644 --- a/modules/messenger/cmd/messenger/main.go +++ b/modules/messenger/cmd/messenger/main.go @@ -33,8 +33,8 @@ type Settings struct { // with nothing held and nothing open is not told there at all (novox/hq ADR 0308 §4). OnlyWhatNeedsMe []string `json:"only-what-needs-me"` // MessagesPerHour is the most messages one channel gets in an hour (issue 1476); 0, not given, is - // DefaultCapPerHour. - MessagesPerHour int `json:"messages-per-hour"` + // DefaultCapPerHour; 0 is no cap at all. + MessagesPerHour *int `json:"messages-per-hour"` } // zoneOf is the location a time-zone setting names, or this machine's own when it names none or one @@ -69,7 +69,11 @@ func readSettings(path string) (Settings, error) { switch v := loose["messages-per-hour"].(type) { case nil: case float64: - s.MessagesPerHour = int(v) + n := int(v) + if v < 0 || v != float64(n) { + return s, fmt.Errorf("messages-per-hour is not a whole number of zero or more") + } + s.MessagesPerHour = &n default: return s, fmt.Errorf("messages-per-hour is not a number") } @@ -340,8 +344,13 @@ func main() { } return loc }, - Emit: func(event string, body any) error { return stdio.Emit(event, body) }, - CapPerHour: func() int { return settings().MessagesPerHour }, + Emit: func(event string, body any) error { return stdio.Emit(event, body) }, + CapPerHour: func() int { + if n := settings().MessagesPerHour; n != nil { + return *n + } + return DefaultCapPerHour + }, NeedsOnly: func(kind string) bool { for _, k := range settings().OnlyWhatNeedsMe { if k == kind { diff --git a/modules/messenger/cmd/messenger/outbox.go b/modules/messenger/cmd/messenger/outbox.go index 8eb47538..b8b2c880 100644 --- a/modules/messenger/cmd/messenger/outbox.go +++ b/modules/messenger/cmd/messenger/outbox.go @@ -613,7 +613,8 @@ func (h *Holder) sendNow(ch Channel, key, what string, m Message) bool { // tell is not counted here: it has its own cap (TellCapPerHour) so a burst of tells cannot crowd // out a condition or an ask (ADR 0380 §8). func (h *Holder) allow(channel string) bool { - return h.sentLastHour(channel) < h.capPerHour() + n := h.capPerHour() + return n == 0 || h.sentLastHour(channel) < n } func (h *Holder) sentLastHour(channel string) int { diff --git a/modules/messenger/module.json b/modules/messenger/module.json index 6e7f1adf..60451958 100644 --- a/modules/messenger/module.json +++ b/modules/messenger/module.json @@ -135,8 +135,8 @@ }, "messages-per-hour": { "type": "number", - "description": "The most messages the mesh sends one channel in an hour, in messages per channel per hour; past it the rest are held and said once as one message (not the tell verb, which has its own cap of 10).", - "minimum": 1, + "description": "messages per channel per hour before the rest are held as one; 0 turns the pause off. The tell verb has its own cap of 10 and is not counted here.", + "minimum": 0, "maximum": 1000, "trusted": false, "default": 100