1
0
Fork 0
forked from External/ergo

improvements to message replay code

This commit is contained in:
Shivaram Lingamneni 2019-05-06 23:17:57 -04:00
parent 939729a7c0
commit b11bf503e7
10 changed files with 338 additions and 165 deletions

View file

@ -487,7 +487,7 @@ func (client *Client) tryResume() (success bool) {
}
}
privmsgMatcher := func(item history.Item) bool {
return item.Type == history.Privmsg || item.Type == history.Notice
return item.Type == history.Privmsg || item.Type == history.Notice || item.Type == history.Tagmsg
}
privmsgHistory := oldClient.history.Match(privmsgMatcher, false, 0)
lastDiscarded := oldClient.history.LastDiscarded()
@ -495,8 +495,7 @@ func (client *Client) tryResume() (success bool) {
oldestLostMessage = lastDiscarded
}
for _, item := range privmsgHistory {
// TODO this is the nickmask, fix that
sender := server.clients.Get(item.Nick)
sender := server.clients.Get(stripMaskFromNick(item.Nick))
if sender != nil {
friends.Add(sender)
}
@ -561,8 +560,13 @@ func (client *Client) tryResumeChannels() {
}
func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, complete bool) {
var batchID string
nick := client.Nick()
serverTime := rb.session.capabilities.Has(caps.ServerTime)
if 0 < len(items) {
batchID = rb.StartNestedHistoryBatch(nick)
}
allowTags := rb.session.capabilities.Has(caps.MessageTags)
for _, item := range items {
var command string
switch item.Type {
@ -570,15 +574,23 @@ func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.I
command = "PRIVMSG"
case history.Notice:
command = "NOTICE"
case history.Tagmsg:
if allowTags {
command = "TAGMSG"
} else {
continue
}
default:
continue
}
var tags map[string]string
if serverTime {
tags = map[string]string{"time": item.Time.Format(IRCv3TimestampFormat)}
if allowTags {
tags = item.Tags
}
rb.AddSplitMessageFromClient(item.Nick, item.AccountName, tags, command, nick, item.Message)
}
rb.EndNestedBatch(batchID)
if !complete {
rb.Add(nil, "HistServ", "NOTICE", nick, client.t("Some additional message history may have been lost"))
}
@ -934,19 +946,21 @@ func (client *Client) destroy(beingResumed bool, session *Session) {
return
}
details := client.Details()
// see #235: deduplicating the list of PART recipients uses (comparatively speaking)
// a lot of RAM, so limit concurrency to avoid thrashing
client.server.semaphores.ClientDestroy.Acquire()
defer client.server.semaphores.ClientDestroy.Release()
if beingResumed {
client.server.logger.Debug("quit", fmt.Sprintf("%s is being resumed", client.nick))
client.server.logger.Debug("quit", fmt.Sprintf("%s is being resumed", details.nick))
} else {
client.server.logger.Debug("quit", fmt.Sprintf("%s is no longer on the server", client.nick))
client.server.logger.Debug("quit", fmt.Sprintf("%s is no longer on the server", details.nick))
}
if !beingResumed {
client.server.whoWas.Append(client.WhoWas())
client.server.whoWas.Append(details.WhoWas)
}
// remove from connection limits
@ -963,6 +977,7 @@ func (client *Client) destroy(beingResumed bool, session *Session) {
// clean up monitor state
client.server.monitorManager.RemoveAll(client)
splitQuitMessage := utils.MakeSplitMessage(quitMessage, true)
// clean up channels
friends := make(ClientSet)
for _, channel := range client.Channels() {
@ -972,7 +987,7 @@ func (client *Client) destroy(beingResumed bool, session *Session) {
Type: history.Quit,
Nick: nickMaskString,
AccountName: accountName,
Message: utils.MakeSplitMessage(quitMessage, true),
Message: splitQuitMessage,
})
}
for _, member := range channel.Members() {
@ -1007,14 +1022,14 @@ func (client *Client) destroy(beingResumed bool, session *Session) {
if quitMessage == "" {
quitMessage = "Exited"
}
friend.Send(nil, client.nickMaskString, "QUIT", quitMessage)
friend.sendFromClientInternal(false, splitQuitMessage.Time, splitQuitMessage.Msgid, details.nickMask, details.accountName, nil, "QUIT", quitMessage)
}
}
if !client.exitedSnomaskSent {
if beingResumed {
client.server.snomasks.Send(sno.LocalQuits, fmt.Sprintf(ircfmt.Unescape("%s$r is resuming their connection, old client has been destroyed"), client.nick))
} else {
client.server.snomasks.Send(sno.LocalQuits, fmt.Sprintf(ircfmt.Unescape("%s$r exited the network"), client.nick))
client.server.snomasks.Send(sno.LocalQuits, fmt.Sprintf(ircfmt.Unescape("%s$r exited the network"), details.nick))
}
}
}
@ -1031,15 +1046,7 @@ func (session *Session) sendSplitMsgFromClientInternal(blocking bool, serverTime
}
}
// SendFromClient sends an IRC line coming from a specific client.
// Adds account-tag to the line as well.
func (client *Client) SendFromClient(msgid string, from *Client, tags map[string]string, command string, params ...string) error {
return client.sendFromClientInternal(false, time.Time{}, msgid, from.NickMaskString(), from.AccountName(), tags, command, params...)
}
// this is SendFromClient, but directly exposing nickmask and accountName,
// for things like history replay and CHGHOST where they no longer (necessarily)
// correspond to the current state of a client
// Sends a line with `nickmask` as the prefix, adding `time` and `account` tags if supported
func (client *Client) sendFromClientInternal(blocking bool, serverTime time.Time, msgid string, nickmask, accountName string, tags map[string]string, command string, params ...string) (err error) {
for _, session := range client.Sessions() {
err_ := session.sendFromClientInternal(blocking, serverTime, msgid, nickmask, accountName, tags, command, params...)
@ -1062,7 +1069,10 @@ func (session *Session) sendFromClientInternal(blocking bool, serverTime time.Ti
}
// attach server-time
if session.capabilities.Has(caps.ServerTime) {
msg.SetTag("time", time.Now().UTC().Format(IRCv3TimestampFormat))
if serverTime.IsZero() {
serverTime = time.Now().UTC()
}
msg.SetTag("time", serverTime.Format(IRCv3TimestampFormat))
}
return session.SendRawMessage(msg, blocking)