source: code/trunk/msgstore.go@ 517

Last change on this file since 517 was 516, checked in by hubert, 4 years ago

Implement CHATHISTORY BETWEEN

File size: 2.9 KB
RevLine 
[423]1package soju
2
3import (
[488]4 "bytes"
5 "encoding/base64"
[440]6 "fmt"
[423]7 "time"
8
[488]9 "git.sr.ht/~sircmpwn/go-bare"
[423]10 "gopkg.in/irc.v3"
11)
12
13// messageStore is a per-user store for IRC messages.
[439]14type messageStore interface {
15 Close() error
16 // LastMsgID queries the last message ID for the given network, entity and
17 // date. The message ID returned may not refer to a valid message, but can be
18 // used in history queries.
19 LastMsgID(network *network, entity string, t time.Time) (string, error)
20 LoadLatestID(network *network, entity, id string, limit int) ([]*irc.Message, error)
21 Append(network *network, entity string, msg *irc.Message) (id string, err error)
[423]22}
[440]23
[441]24// chatHistoryMessageStore is a message store that supports chat history
25// operations.
26type chatHistoryMessageStore interface {
27 messageStore
28
[516]29 // LoadBeforeTime loads up to limit messages before start down to end. The
30 // returned messages must be between and excluding the provided bounds.
31 // end is before start.
32 LoadBeforeTime(network *network, entity string, start, end time.Time, limit int) ([]*irc.Message, error)
33 // LoadBeforeTime loads up to limit messages after start up to end. The
34 // returned messages must be between and excluding the provided bounds.
35 // end is after start.
36 LoadAfterTime(network *network, entity string, start, end time.Time, limit int) ([]*irc.Message, error)
[441]37}
38
[488]39type msgIDType uint
40
41const (
42 msgIDNone msgIDType = iota
43 msgIDMemory
44 msgIDFS
45)
46
47const msgIDVersion uint = 0
48
49type msgIDHeader struct {
50 Version uint
51 Network bare.Int
52 Target string
53 Type msgIDType
[440]54}
55
[488]56type msgIDBody interface {
57 msgIDType() msgIDType
58}
59
60func formatMsgID(netID int64, target string, body msgIDBody) string {
61 var buf bytes.Buffer
62 w := bare.NewWriter(&buf)
63
64 header := msgIDHeader{
65 Version: msgIDVersion,
66 Network: bare.Int(netID),
67 Target: target,
68 Type: body.msgIDType(),
[440]69 }
[488]70 if err := bare.MarshalWriter(w, &header); err != nil {
71 panic(err)
72 }
73 if err := bare.MarshalWriter(w, body); err != nil {
74 panic(err)
75 }
76 return base64.RawURLEncoding.EncodeToString(buf.Bytes())
77}
78
79func parseMsgID(s string, body msgIDBody) (netID int64, target string, err error) {
80 b, err := base64.RawURLEncoding.DecodeString(s)
[440]81 if err != nil {
[488]82 return 0, "", fmt.Errorf("invalid internal message ID: %v", err)
[440]83 }
[488]84
85 r := bare.NewReader(bytes.NewReader(b))
86
87 var header msgIDHeader
88 if err := bare.UnmarshalBareReader(r, &header); err != nil {
89 return 0, "", fmt.Errorf("invalid internal message ID: %v", err)
90 }
91
92 if header.Version != msgIDVersion {
93 return 0, "", fmt.Errorf("invalid internal message ID: got version %v, want %v", header.Version, msgIDVersion)
94 }
95
96 if body != nil {
97 typ := body.msgIDType()
98 if header.Type != typ {
99 return 0, "", fmt.Errorf("invalid internal message ID: got type %v, want %v", header.Type, typ)
100 }
101
102 if err := bare.UnmarshalBareReader(r, body); err != nil {
103 return 0, "", fmt.Errorf("invalid internal message ID: %v", err)
104 }
105 }
106
107 return int64(header.Network), header.Target, nil
[440]108}
Note: See TracBrowser for help on using the repository browser.