diff --git a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/record.go b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/record.go index 38b81225a..f99abaa03 100644 --- a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/record.go +++ b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/record.go @@ -21,6 +21,7 @@ import ( "sync" "time" + "git.novox.be/novox/mesh-delivery/contracts/go/seats/meshdelivery" stdio "git.novox.be/novox/mesh-sdk/go" "git.novox.be/novox/mesh-sdk/go/buscalls" ) @@ -498,10 +499,24 @@ func (rs *Records) Open(milestone string, heads map[string]string, forgeMade boo r, err = rs.Read(inst) if err == nil && r != nil { rs.keep(r) + // Said once, under the record's id: the watchman times it against 24 hours, ended by record-ended. A say that fails is + // said again by the next write of the record (the id keeps it once). + if serr := rs.say(meshdelivery.SubjectRecordOpened, recordOpened{Record: inst, Milestone: milestone, ForgeMade: forgeMade, At: now.UTC()}, + "record-opened."+inst); serr != nil && rs.Logf != nil { + rs.Logf("[mesh-delivery] the record %s is opened and its opening is not said: %v", inst, serr) + } } return r, err == nil && r != nil, err } +// recordOpened is the body of the seat's event record-opened. +type recordOpened struct { + Record string `json:"record"` + Milestone string `json:"milestone"` + ForgeMade bool `json:"forge-made,omitempty"` + At time.Time `json:"at"` +} + // List is every record kept, opened within the retention and a month more, oldest first. func (rs *Records) List() ([]*Record, error) { now := rs.now() diff --git a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/record_test.go b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/record_test.go index 87efb4b97..fcbb9336f 100644 --- a/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/record_test.go +++ b/modules/mesh-delivery-gate/cmd/mesh-delivery-gate/record_test.go @@ -290,6 +290,9 @@ func TestTheDeliveryRecordIsALedgerInstanceKeyedByMilestoneAndHeads(t *testing.T } var got []said rs := &Records{Ledger: l, Now: func() time.Time { return at }, Say: func(subject string, body any, id string) error { + if subject == meshdelivery.SubjectRecordOpened { + return nil + } got = append(got, said{subject, id, body.(meshdelivery.Pins)}) return nil }} @@ -694,7 +697,11 @@ func TestTheRecordsToolsReadThemAndEndOneByHand(t *testing.T) { return rs, r, &said } t.Run("gate_record and gate_records read a record whole and its fill", func(t *testing.T) { - rs, r, _ := setup(t) + rs, r, said := setup(t) + // W9.3: the record's opening is said once, under its id, for the watchman to time against 24 hours. + if !slices.Contains(*said, meshdelivery.SubjectRecordOpened+" record-opened."+r.Instance) { + t.Fatalf("the record's opening is not said: %v", *said) + } got, err := rs.RecordOf(r.Instance, "") if err != nil || len(got) != 1 || got[0].Record.Milestone != "47/G" || got[0].Waits != "waiting for mesh-x on ace" || got[0].Bytes == 0 || got[0].Of != 256<<10 { @@ -769,6 +776,9 @@ func TestTheRecordsLedgerSaysFillingFullAndRoom(t *testing.T) { } saying := func(out *[]said) SeatSay { return func(subject string, body any, id string) error { + if subject == meshdelivery.SubjectRecordOpened { + return nil // the opening of a record, not a fill + } f, _ := body.(meshdelivery.Fill) *out = append(*out, said{subject, id, f}) return nil