"note": true,
}
+// Log is the append-only message log of one chat. It writes one JSON line for
+// each message to main/YYYY-MM-DD.jsonl, named for the local day of the
+// message. It never edits or deletes a line. Each line goes to the operating
+// system before Append returns, so a crash of the process loses no message. An
+// exclusive lock on the lock file makes sure that only one process writes the
+// log. After a failed write, the end of the file is not known, so the log
+// refuses all writes until it is opened again. The caller serializes all calls.
+//
+// The log keeps no message in memory. The index index/main.idx holds the
+// position of message i in record i, so a read of a message is one read of the
+// index and one of its day file. At open the log indexes the lines after the
+// last indexed one, so a missing index is built again from the day files.
+type Log struct {
+ clock func() time.Time
+ lock *os.File
+ journal Journal
+ index *Records
+ failure error
+}
+
+// Message is one entry of the chat log. ID is its position in the log, from 0.
+// A rebuild assigns positions in the merged log. Size is the UTF-8 byte length
+// of Text. Date is the message time in RFC 3339 format, supplied at append or
+// taken from the clock.
+type Message struct {
+ ID int `json:"i"`
+ Kind string `json:"kind"`
+ Text string `json:"text"`
+ Size int `json:"size"`
+ Date string `json:"date"`
+}
+
// openLog locks the chat in root and indexes its new lines. The clock gives the
// date of each new message.
func openLog(ctx context.Context, root string, clock func() time.Time) (*Log, error) {
return l, nil
}
-// Log is the append-only message log of one chat. It writes one JSON line for
-// each message to main/YYYY-MM-DD.jsonl, named for the local day of the
-// message. It never edits or deletes a line. Each line goes to the operating
-// system before Append returns, so a crash of the process loses no message. An
-// exclusive lock on the lock file makes sure that only one process writes the
-// log. After a failed write, the end of the file is not known, so the log
-// refuses all writes until it is opened again. The caller serializes all calls.
-//
-// The log keeps no message in memory. The index index/main.idx holds the
-// position of message i in record i, so a read of a message is one read of the
-// index and one of its day file. At open the log indexes the lines after the
-// last indexed one, so a missing index is built again from the day files.
-type Log struct {
- clock func() time.Time
- lock *os.File
- journal Journal
- index *Records
- failure error
-}
-
// Close releases the lock. The log refuses all calls after Close.
func (l *Log) Close() error {
err := l.journal.Close()
}
var err error
+
now := l.clock()
if date == "" {
date = now.Format(time.RFC3339Nano)
}
var message Message
+
err = json.Unmarshal(line, &message)
if err != nil {
return Message{}, fmt.Errorf("decode message %d: %w", id, err)
return l.journal.Scan(ctx, start, func(line []byte, place Position) error {
var message Message
+
err := json.Unmarshal(line, &message)
if err != nil {
- return err
+ return fmt.Errorf("decode log message: %w", err)
}
if message.ID != l.index.count {
return l.index.Append(record)
}
-// Message is one entry of the chat log. ID is its position in the log, from 0.
-// A rebuild assigns positions in the merged log. Size is the UTF-8 byte length
-// of Text. Date is the message time in RFC 3339 format, supplied at append or
-// taken from the clock.
-type Message struct {
- ID int `json:"i"`
- Kind string `json:"kind"`
- Text string `json:"text"`
- Size int `json:"size"`
- Date string `json:"date"`
-}
-
// logValidateMessage makes sure that a message has a known kind, valid UTF-8
// text, the size of its text, and a valid date.
func logValidateMessage(message Message) error {