// the batches that are not in the log yet and the records of the sends.
whatsappStateFileName = "state.json"
- // whatsappBatchQuiet is how long a chat is quiet before its batch
+ // whatsappBatchIdleTimeout is how long a chat is quiet before its batch
// closes.
- whatsappBatchQuiet = 20 * time.Second
+ whatsappBatchIdleTimeout = 20 * time.Second
- // whatsappBatchWindow is the longest time of a batch.
- whatsappBatchWindow = 2 * time.Minute
+ // whatsappBatchTimeout is the longest time of a batch.
+ whatsappBatchTimeout = 2 * time.Minute
// whatsappBatchMessages is the most messages of a batch.
whatsappBatchMessages = 50
whatsappSendRecords = 1000
)
+// WhatsAppState holds the state file: the send records, and the batches of the
+// WhatsApp messages that are not in the log yet, open and closed, in the order
+// of their first message. The messages of one chat form one batch while the
+// times of the messages are at most whatsappBatchIdleTimeout apart, at most
+// whatsappBatchTimeout after the first, and the batch has fewer than
+// whatsappBatchMessages messages. The times are the WhatsApp times, so a
+// catch-up after a stop gives the same batches as live messages. A batch also
+// closes when whatsappBatchIdleTimeout passes after the arrival of its last
+// message, or whatsappBatchTimeout after the arrival of its first message, in
+// real time.
+//
+// A send record keeps the result of a send by its ID, so that a repeated call
+// of the send tool does not send again. The state file keeps the last
+// whatsappSendRecords records.
+//
+// Each change writes the state file whole, so the batches and the records
+// survive a restart. The mutex protects them, because the event handler of the
+// library adds messages while Run closes and removes batches, and the turns
+// send.
+type WhatsAppState struct {
+ path string
+
+ mutex sync.Mutex
+ file WhatsAppStateFile
+}
+
+// WhatsAppStateFile is the content of the state file: the number of the last
+// batch, the batches that are not in the log yet, and the send records, oldest
+// first.
+type WhatsAppStateFile struct {
+ Next int `json:"next"`
+ Batches []WhatsAppBatch `json:"batches"`
+ Sends []WhatsAppSend `json:"sends"`
+}
+
+// WhatsAppSend is the record of one send: the ID that the agent gave, the chat,
+// the SHA-256 of the text, an optional stored image name, the WhatsApp message
+// ID, the state, which is sending, sent, or failed, the answer of the tool, and
+// the time of its start.
+type WhatsAppSend struct {
+ ID string `json:"id"`
+ Chat string `json:"chat"`
+ Digest string `json:"digest"`
+ Image string `json:"image,omitempty"`
+ MessageID string `json:"message_id"`
+ State string `json:"state"`
+ Answer string `json:"answer,omitempty"`
+ Time time.Time `json:"time"`
+}
+
// openWhatsAppState reads the batches and the send records of the state file at
-// path. A missing file holds none. A batch closes after quiet with no message,
-// or after window at the latest.
-func openWhatsAppState(path string, quiet, window time.Duration) (*WhatsAppState, error) {
+// path. A missing file holds none. A batch closes after
+// whatsappBatchIdleTimeout with no message, or after whatsappBatchTimeout at
+// the latest.
+func openWhatsAppState(path string) (*WhatsAppState, error) {
s := &WhatsAppState{
- path: path,
- quiet: quiet,
- window: window,
+ path: path,
}
data, err := os.ReadFile(path)
return s, nil
}
-// WhatsAppState holds the state file: the send records, and the batches of the
-// WhatsApp messages that are not in the log yet, open and closed, in the order
-// of their first message. The messages of one chat form one batch while the
-// times of the messages are at most quiet apart, at most window after the
-// first, and the batch has fewer than whatsappBatchMessages messages. The times
-// are the WhatsApp times, so a catch-up after a stop gives the same batches as
-// live messages. A batch also closes when quiet passes after the arrival of its
-// last message, or window after the arrival of its first message, in real time.
-//
-// A send record keeps the result of a send by its ID, so that a repeated call
-// of the send tool does not send again. The state file keeps the last
-// whatsappSendRecords records.
-//
-// Each change writes the state file whole, so the batches and the records
-// survive a restart. The mutex protects them, because the event handler of the
-// library adds messages while Run closes and removes batches, and the turns
-// send.
-type WhatsAppState struct {
- path string
- quiet time.Duration
- window time.Duration
-
- mutex sync.Mutex
- file WhatsAppStateFile
-}
-
// Add puts message of chat into the open batch of chat, or into a new batch,
// with arrival as its time of arrival. A message that the batch holds already,
// which the servers sent again, changes nothing. It returns true when a batch
return false, nil
}
- if message.Time.Sub(batch.Messages[len(batch.Messages)-1].Time) > s.quiet || message.Time.Sub(batch.Messages[0].Time) > s.window {
+ if message.Time.Sub(batch.Messages[len(batch.Messages)-1].Time) > whatsappBatchIdleTimeout || message.Time.Sub(batch.Messages[0].Time) > whatsappBatchTimeout {
batch.Closed = true
closed = true
index = -1
defer s.mutex.Unlock()
var closed []WhatsAppBatch
+
for _, batch := range s.file.Batches {
if batch.Closed {
closed = append(closed, batch)
defer s.mutex.Unlock()
var first time.Time
+
for _, batch := range s.file.Batches {
deadline := s.deadline(batch)
if !batch.Closed && (first.IsZero() || deadline.Before(first)) {
// deadline returns when batch closes in real time.
func (s *WhatsAppState) deadline(batch WhatsAppBatch) time.Time {
- quiet := batch.Last.Add(s.quiet)
- window := batch.First.Add(s.window)
+ quiet := batch.Last.Add(whatsappBatchIdleTimeout)
+ window := batch.First.Add(whatsappBatchTimeout)
if window.Before(quiet) {
return window
}
return nil
}
-
-// WhatsAppStateFile is the content of the state file: the number of the last
-// batch, the batches that are not in the log yet, and the send records, oldest
-// first.
-type WhatsAppStateFile struct {
- Next int `json:"next"`
- Batches []WhatsAppBatch `json:"batches"`
- Sends []WhatsAppSend `json:"sends"`
-}
-
-// WhatsAppSend is the record of one send: the ID that the agent gave, the chat,
-// the SHA-256 of the text, the WhatsApp message ID, the state, which is
-// sending, sent, or failed, the answer of the tool, and the time of its start.
-type WhatsAppSend struct {
- ID string `json:"id"`
- Chat string `json:"chat"`
- Digest string `json:"digest"`
- MessageID string `json:"message_id"`
- State string `json:"state"`
- Answer string `json:"answer,omitempty"`
- Time time.Time `json:"time"`
-}