Implement CHATHISTORY AFTER
References: https://todo.sr.ht/~emersion/soju/12
This commit is contained in:
parent
25d4312e0f
commit
dcfe206bda
@ -1598,9 +1598,10 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
}}
|
||||
}
|
||||
|
||||
batchRef := "history"
|
||||
maxTries := 100
|
||||
switch subcommand {
|
||||
case "BEFORE":
|
||||
batchRef := "history"
|
||||
dc.SendMessage(&irc.Message{
|
||||
Prefix: dc.srv.prefix(),
|
||||
Command: "BATCH",
|
||||
@ -1611,7 +1612,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
remaining := limit
|
||||
|
||||
tries := 0
|
||||
for remaining > 0 {
|
||||
for remaining > 0 && tries < maxTries {
|
||||
buf, err := parseMessagesBefore(uc.network, entity, timestamp, remaining)
|
||||
if err != nil {
|
||||
dc.logger.Printf("failed parsing log messages for chathistory: %v", err)
|
||||
@ -1619,9 +1620,6 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
}
|
||||
if len(buf) == 0 {
|
||||
tries++
|
||||
if tries >= 100 {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
tries = 0
|
||||
}
|
||||
@ -1631,9 +1629,44 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
timestamp = time.Date(year, month, day, 0, 0, 0, 0, timestamp.Location()).Add(-1)
|
||||
}
|
||||
|
||||
for _, m := range history[remaining:] {
|
||||
m.Tags["batch"] = irc.TagValue(batchRef)
|
||||
dc.SendMessage(dc.marshalMessage(m, uc.network))
|
||||
for _, msg := range history[remaining:] {
|
||||
msg.Tags["batch"] = irc.TagValue(batchRef)
|
||||
dc.SendMessage(dc.marshalMessage(msg, uc.network))
|
||||
}
|
||||
|
||||
dc.SendMessage(&irc.Message{
|
||||
Prefix: dc.srv.prefix(),
|
||||
Command: "BATCH",
|
||||
Params: []string{"-" + batchRef},
|
||||
})
|
||||
case "AFTER":
|
||||
dc.SendMessage(&irc.Message{
|
||||
Prefix: dc.srv.prefix(),
|
||||
Command: "BATCH",
|
||||
Params: []string{"+" + batchRef, "chathistory", target},
|
||||
})
|
||||
|
||||
remaining := limit
|
||||
tries := 0
|
||||
now := time.Now()
|
||||
for remaining > 0 && tries < maxTries && timestamp.Before(now) {
|
||||
buf, err := parseMessagesAfter(uc.network, entity, timestamp, remaining)
|
||||
if err != nil {
|
||||
dc.logger.Printf("failed parsing log messages for chathistory: %v", err)
|
||||
return newChatHistoryError(subcommand, target)
|
||||
}
|
||||
if len(buf) == 0 {
|
||||
tries++
|
||||
} else {
|
||||
tries = 0
|
||||
}
|
||||
for _, msg := range buf {
|
||||
msg.Tags["batch"] = irc.TagValue(batchRef)
|
||||
dc.SendMessage(dc.marshalMessage(msg, uc.network))
|
||||
}
|
||||
remaining -= len(buf)
|
||||
year, month, day := timestamp.Date()
|
||||
timestamp = time.Date(year, month, day + 1, 0, 0, 0, 0, timestamp.Location())
|
||||
}
|
||||
|
||||
dc.SendMessage(&irc.Message{
|
||||
@ -1642,7 +1675,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
||||
Params: []string{"-" + batchRef},
|
||||
})
|
||||
default:
|
||||
// TODO: support AFTER, LATEST, BETWEEN
|
||||
// TODO: support LATEST, BETWEEN
|
||||
return ircError{&irc.Message{
|
||||
Command: "FAIL",
|
||||
Params: []string{"CHATHISTORY", "UNKNOWN_COMMAND", subcommand, "Unknown command"},
|
||||
|
98
logger.go
98
logger.go
@ -134,9 +134,41 @@ func formatMessage(msg *irc.Message) string {
|
||||
}
|
||||
}
|
||||
|
||||
func parseMessagesBefore(network *network, entity string, timestamp time.Time, limit int) ([]*irc.Message, error) {
|
||||
year, month, day := timestamp.Date()
|
||||
path := logPath(network, entity, timestamp)
|
||||
func parseMessage(line, entity string, ref time.Time) (*irc.Message, time.Time, error) {
|
||||
var hour, minute, second int
|
||||
_, err := fmt.Sscanf(line, "[%02d:%02d:%02d] ", &hour, &minute, &second)
|
||||
if err != nil {
|
||||
return nil, time.Time{}, err
|
||||
}
|
||||
line = line[11:]
|
||||
|
||||
// TODO: support NOTICE
|
||||
if !strings.HasPrefix(line, "<") {
|
||||
return nil, time.Time{}, nil
|
||||
}
|
||||
i := strings.Index(line, "> ")
|
||||
if i < 0 {
|
||||
return nil, time.Time{}, nil
|
||||
}
|
||||
|
||||
year, month, day := ref.Date()
|
||||
t := time.Date(year, month, day, hour, minute, second, 0, time.Local)
|
||||
|
||||
sender := line[1:i]
|
||||
text := line[i+2:]
|
||||
msg := &irc.Message{
|
||||
Tags: map[string]irc.TagValue{
|
||||
"time": irc.TagValue(t.UTC().Format(serverTimeLayout)),
|
||||
},
|
||||
Prefix: &irc.Prefix{Name: sender},
|
||||
Command: "PRIVMSG",
|
||||
Params: []string{entity, text},
|
||||
}
|
||||
return msg, t, nil
|
||||
}
|
||||
|
||||
func parseMessagesBefore(network *network, entity string, ref time.Time, limit int) ([]*irc.Message, error) {
|
||||
path := logPath(network, entity, ref)
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
@ -151,38 +183,16 @@ func parseMessagesBefore(network *network, entity string, timestamp time.Time, l
|
||||
|
||||
sc := bufio.NewScanner(f)
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
var hour, minute, second int
|
||||
_, err := fmt.Sscanf(line, "[%02d:%02d:%02d] ", &hour, &minute, &second)
|
||||
msg, t, err := parseMessage(sc.Text(), entity, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
message := line[11:]
|
||||
// TODO: support NOTICE
|
||||
if !strings.HasPrefix(message, "<") {
|
||||
} else if msg == nil {
|
||||
continue
|
||||
}
|
||||
i := strings.Index(message, "> ")
|
||||
if i == -1 {
|
||||
continue
|
||||
}
|
||||
t := time.Date(year, month, day, hour, minute, second, 0, time.Local)
|
||||
if !t.Before(timestamp) {
|
||||
} else if !t.Before(ref) {
|
||||
break
|
||||
}
|
||||
|
||||
sender := message[1:i]
|
||||
text := message[i+2:]
|
||||
historyRing[cur%limit] = &irc.Message{
|
||||
Tags: map[string]irc.TagValue{
|
||||
"time": irc.TagValue(t.UTC().Format(serverTimeLayout)),
|
||||
},
|
||||
Prefix: &irc.Prefix{
|
||||
Name: sender,
|
||||
},
|
||||
Command: "PRIVMSG",
|
||||
Params: []string{entity, text},
|
||||
}
|
||||
historyRing[cur%limit] = msg
|
||||
cur++
|
||||
}
|
||||
if sc.Err() != nil {
|
||||
@ -204,3 +214,33 @@ func parseMessagesBefore(network *network, entity string, timestamp time.Time, l
|
||||
return history, nil
|
||||
}
|
||||
}
|
||||
|
||||
func parseMessagesAfter(network *network, entity string, ref time.Time, limit int) ([]*irc.Message, error) {
|
||||
path := logPath(network, entity, ref)
|
||||
f, err := os.Open(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return nil, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var history []*irc.Message
|
||||
sc := bufio.NewScanner(f)
|
||||
for sc.Scan() && len(history) < limit {
|
||||
msg, t, err := parseMessage(sc.Text(), entity, ref)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if msg == nil || !t.After(ref) {
|
||||
continue
|
||||
}
|
||||
|
||||
history = append(history, msg)
|
||||
}
|
||||
if sc.Err() != nil {
|
||||
return nil, sc.Err()
|
||||
}
|
||||
|
||||
return history, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user