X-Git-Url: http://git.giacomolli.uk/onechat/blobdiff_plain/6844f8c992ec4e276a3a0d93b544de0127eebbd2..723f6e18adc6482ed913e1618c8a76e981720c2b:/memory.go?ds=sidebyside diff --git a/memory.go b/memory.go index c9fe1c5..a240b6c 100644 --- a/memory.go +++ b/memory.go @@ -149,6 +149,11 @@ func (m *Memory) AppendDated(kind, text, date string) (Message, error) { m.mutex.Lock() defer m.mutex.Unlock() + return m.appendDated(kind, text, date) +} + +// appendDated appends under the memory lock and updates the views and builds. +func (m *Memory) appendDated(kind, text, date string) (Message, error) { message, err := m.log.AppendDated(kind, text, date) if err != nil { return Message{}, fmt.Errorf("append dated log message: %w", err) @@ -172,6 +177,44 @@ func (m *Memory) AppendDated(kind, text, date string) (Message, error) { return message, nil } +// AppendOnce appends a queued message. prepare saves its log ID before the +// append, under the memory lock. A saved ID permits recovery after a stop +// between that save and the append, without a second log entry. prepare must +// not call Memory. The caller stops delivery after a failed append. +func (m *Memory) AppendOnce(kind, text string, id *int, prepare func(int) error) (Message, error) { + m.mutex.Lock() + defer m.mutex.Unlock() + + if id != nil && *id < m.log.Len() { + message, err := m.log.Message(*id) + if err != nil { + return Message{}, fmt.Errorf("read queued message: %w", err) + } + + if message.Kind != kind || message.Text != text { + return Message{}, errors.New("queued message does not match its log entry") + } + + return message, nil + } + + if id != nil && *id != m.log.Len() { + return Message{}, errors.New("queued message is beyond the log") + } + + err := prepare(m.log.Len()) + if err != nil { + return Message{}, fmt.Errorf("prepare queued message: %w", err) + } + + message, err := m.appendDated(kind, text, "") + if err != nil { + return Message{}, fmt.Errorf("append queued message: %w", err) + } + + return message, nil +} + // children reads the two children of the node key. func (m *Memory) children(key NodeKey) (Node, Node, error) { var children [2]Node