source: code/trunk/msgstore.go@ 738

Last change on this file since 738 was 667, checked in by contact, 4 years ago

msgstore: add context to messageStore methods

This allows setting a hard timeout.

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