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 {
|
switch subcommand {
|
||||||
case "BEFORE":
|
case "BEFORE":
|
||||||
batchRef := "history"
|
|
||||||
dc.SendMessage(&irc.Message{
|
dc.SendMessage(&irc.Message{
|
||||||
Prefix: dc.srv.prefix(),
|
Prefix: dc.srv.prefix(),
|
||||||
Command: "BATCH",
|
Command: "BATCH",
|
||||||
@ -1611,7 +1612,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
|||||||
remaining := limit
|
remaining := limit
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
for remaining > 0 {
|
for remaining > 0 && tries < maxTries {
|
||||||
buf, err := parseMessagesBefore(uc.network, entity, timestamp, remaining)
|
buf, err := parseMessagesBefore(uc.network, entity, timestamp, remaining)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
dc.logger.Printf("failed parsing log messages for chathistory: %v", err)
|
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 {
|
if len(buf) == 0 {
|
||||||
tries++
|
tries++
|
||||||
if tries >= 100 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
tries = 0
|
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)
|
timestamp = time.Date(year, month, day, 0, 0, 0, 0, timestamp.Location()).Add(-1)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range history[remaining:] {
|
for _, msg := range history[remaining:] {
|
||||||
m.Tags["batch"] = irc.TagValue(batchRef)
|
msg.Tags["batch"] = irc.TagValue(batchRef)
|
||||||
dc.SendMessage(dc.marshalMessage(m, uc.network))
|
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{
|
dc.SendMessage(&irc.Message{
|
||||||
@ -1642,7 +1675,7 @@ func (dc *downstreamConn) handleMessageRegistered(msg *irc.Message) error {
|
|||||||
Params: []string{"-" + batchRef},
|
Params: []string{"-" + batchRef},
|
||||||
})
|
})
|
||||||
default:
|
default:
|
||||||
// TODO: support AFTER, LATEST, BETWEEN
|
// TODO: support LATEST, BETWEEN
|
||||||
return ircError{&irc.Message{
|
return ircError{&irc.Message{
|
||||||
Command: "FAIL",
|
Command: "FAIL",
|
||||||
Params: []string{"CHATHISTORY", "UNKNOWN_COMMAND", subcommand, "Unknown command"},
|
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) {
|
func parseMessage(line, entity string, ref time.Time) (*irc.Message, time.Time, error) {
|
||||||
year, month, day := timestamp.Date()
|
var hour, minute, second int
|
||||||
path := logPath(network, entity, timestamp)
|
_, 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)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
@ -151,38 +183,16 @@ func parseMessagesBefore(network *network, entity string, timestamp time.Time, l
|
|||||||
|
|
||||||
sc := bufio.NewScanner(f)
|
sc := bufio.NewScanner(f)
|
||||||
for sc.Scan() {
|
for sc.Scan() {
|
||||||
line := sc.Text()
|
msg, t, err := parseMessage(sc.Text(), entity, ref)
|
||||||
var hour, minute, second int
|
|
||||||
_, err := fmt.Sscanf(line, "[%02d:%02d:%02d] ", &hour, &minute, &second)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
} else if msg == nil {
|
||||||
message := line[11:]
|
|
||||||
// TODO: support NOTICE
|
|
||||||
if !strings.HasPrefix(message, "<") {
|
|
||||||
continue
|
continue
|
||||||
}
|
} else if !t.Before(ref) {
|
||||||
i := strings.Index(message, "> ")
|
|
||||||
if i == -1 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
t := time.Date(year, month, day, hour, minute, second, 0, time.Local)
|
|
||||||
if !t.Before(timestamp) {
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
sender := message[1:i]
|
historyRing[cur%limit] = msg
|
||||||
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},
|
|
||||||
}
|
|
||||||
cur++
|
cur++
|
||||||
}
|
}
|
||||||
if sc.Err() != nil {
|
if sc.Err() != nil {
|
||||||
@ -204,3 +214,33 @@ func parseMessagesBefore(network *network, entity string, timestamp time.Time, l
|
|||||||
return history, nil
|
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