3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-11-22 03:49:27 +01:00

Merge pull request #1809 from slingamn/issue1676_again.3

fix #1676, take 2
This commit is contained in:
Shivaram Lingamneni 2021-11-02 03:51:04 -04:00 committed by GitHub
commit c9b54ee2b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 104 additions and 127 deletions

View File

@ -2294,7 +2294,6 @@ type ReplayJoinsSetting uint
const ( const (
ReplayJoinsCommandsOnly = iota // replay in HISTORY or CHATHISTORY output ReplayJoinsCommandsOnly = iota // replay in HISTORY or CHATHISTORY output
ReplayJoinsAlways // replay in HISTORY, CHATHISTORY, or autoreplay ReplayJoinsAlways // replay in HISTORY, CHATHISTORY, or autoreplay
ReplayJoinsNever // never replay
) )
func replayJoinsSettingFromString(str string) (result ReplayJoinsSetting, err error) { func replayJoinsSettingFromString(str string) (result ReplayJoinsSetting, err error) {
@ -2303,8 +2302,6 @@ func replayJoinsSettingFromString(str string) (result ReplayJoinsSetting, err er
result = ReplayJoinsCommandsOnly result = ReplayJoinsCommandsOnly
case "always": case "always":
result = ReplayJoinsAlways result = ReplayJoinsAlways
case "never":
result = ReplayJoinsNever
default: default:
err = errInvalidParams err = errInvalidParams
} }

View File

@ -917,7 +917,7 @@ func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, sk
} }
if hasAutoreplayTimestamps { if hasAutoreplayTimestamps {
_, seq, _ := channel.server.GetHistorySequence(channel, client, "", 0) _, seq, _ := channel.server.GetHistorySequence(channel, client, "")
if seq != nil { if seq != nil {
zncMax := channel.server.Config().History.ZNCMax zncMax := channel.server.Config().History.ZNCMax
items, _ = seq.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax) items, _ = seq.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax)
@ -935,7 +935,7 @@ func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, sk
replayLimit = channel.server.Config().History.AutoreplayOnJoin replayLimit = channel.server.Config().History.AutoreplayOnJoin
} }
if 0 < replayLimit { if 0 < replayLimit {
_, seq, _ := channel.server.GetHistorySequence(channel, client, "", 0) _, seq, _ := channel.server.GetHistorySequence(channel, client, "")
if seq != nil { if seq != nil {
items, _ = seq.Between(history.Selector{}, history.Selector{}, replayLimit) items, _ = seq.Between(history.Selector{}, history.Selector{}, replayLimit)
} }
@ -952,7 +952,7 @@ func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, sk
} }
} }
if 0 < numItems { if 0 < numItems {
channel.replayHistoryItems(rb, items, true) channel.replayHistoryItems(rb, items, false)
rb.Flush(true) rb.Flush(true)
} }
} }
@ -1035,7 +1035,7 @@ func (channel *Channel) Part(client *Client, message string, rb *ResponseBuffer)
client.server.logger.Debug("channels", fmt.Sprintf("%s left channel %s", details.nick, chname)) client.server.logger.Debug("channels", fmt.Sprintf("%s left channel %s", details.nick, chname))
} }
func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, autoreplay bool) { func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.Item, chathistoryCommand bool) {
// send an empty batch if necessary, as per the CHATHISTORY spec // send an empty batch if necessary, as per the CHATHISTORY spec
chname := channel.Name() chname := channel.Name()
client := rb.target client := rb.target
@ -1043,13 +1043,15 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
extendedJoin := rb.session.capabilities.Has(caps.ExtendedJoin) extendedJoin := rb.session.capabilities.Has(caps.ExtendedJoin)
var playJoinsAsPrivmsg bool var playJoinsAsPrivmsg bool
if !eventPlayback { if !eventPlayback {
switch client.AccountSettings().ReplayJoins { if chathistoryCommand {
case ReplayJoinsCommandsOnly:
playJoinsAsPrivmsg = !autoreplay
case ReplayJoinsAlways:
playJoinsAsPrivmsg = true playJoinsAsPrivmsg = true
case ReplayJoinsNever: } else {
playJoinsAsPrivmsg = false switch client.AccountSettings().ReplayJoins {
case ReplayJoinsCommandsOnly:
playJoinsAsPrivmsg = false
case ReplayJoinsAlways:
playJoinsAsPrivmsg = true
}
} }
} }
@ -1066,6 +1068,9 @@ func (channel *Channel) replayHistoryItems(rb *ResponseBuffer, items []history.I
case history.Tagmsg: case history.Tagmsg:
if eventPlayback { if eventPlayback {
rb.AddSplitMessageFromClient(item.Nick, item.AccountName, item.IsBot, item.Tags, "TAGMSG", chname, item.Message) rb.AddSplitMessageFromClient(item.Nick, item.AccountName, item.IsBot, item.Tags, "TAGMSG", chname, item.Message)
} else if chathistoryCommand {
// #1676, we have to send something here or else it breaks pagination
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", chname, fmt.Sprintf(client.t("%s sent a TAGMSG"), nick))
} }
case history.Join: case history.Join:
if eventPlayback { if eventPlayback {

View File

@ -853,7 +853,7 @@ func (session *Session) Ping() {
session.Send(nil, "", "PING", session.client.Nick()) session.Send(nil, "", "PING", session.client.Nick())
} }
func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string) { func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.Item, target string, chathistoryCommand bool) {
var batchID string var batchID string
details := client.Details() details := client.Details()
nick := details.nick nick := details.nick
@ -893,10 +893,15 @@ func (client *Client) replayPrivmsgHistory(rb *ResponseBuffer, items []history.I
case history.Tagmsg: case history.Tagmsg:
if hasEventPlayback && hasTags { if hasEventPlayback && hasTags {
command = "TAGMSG" command = "TAGMSG"
} else if chathistoryCommand {
// #1676: send something for TAGMSG; we can't discard it entirely
// because it'll break pagination
rb.AddFromClient(item.Message.Time, history.HistservMungeMsgid(item.Message.Msgid), histservService.prefix, "*", false, nil, "PRIVMSG", fmt.Sprintf(client.t("%[1]s sent you a TAGMSG"), NUHToNick(item.Nick)))
} else { } else {
continue continue
} }
default: default:
// see #1676, this shouldn't happen
continue continue
} }
var tags map[string]string var tags map[string]string
@ -1713,7 +1718,7 @@ func (client *Client) listTargets(start, end history.Selector, limit int) (resul
var base, extras []history.TargetListing var base, extras []history.TargetListing
var chcfnames []string var chcfnames []string
for _, channel := range client.Channels() { for _, channel := range client.Channels() {
_, seq, err := client.server.GetHistorySequence(channel, client, "", 0) _, seq, err := client.server.GetHistorySequence(channel, client, "")
if seq == nil || err != nil { if seq == nil || err != nil {
continue continue
} }
@ -1734,7 +1739,7 @@ func (client *Client) listTargets(start, end history.Selector, limit int) (resul
extras = append(extras, persistentExtras...) extras = append(extras, persistentExtras...)
} }
_, cSeq, err := client.server.GetHistorySequence(nil, client, "", 0) _, cSeq, err := client.server.GetHistorySequence(nil, client, "")
if err == nil && cSeq != nil { if err == nil && cSeq != nil {
correspondents, err := cSeq.ListCorrespondents(start, end, limit) correspondents, err := cSeq.ListCorrespondents(start, end, limit)
if err == nil { if err == nil {
@ -1758,7 +1763,7 @@ func (client *Client) privmsgsBetween(startTime, endTime time.Time, targetLimit,
if strings.HasPrefix(target.CfName, "#") { if strings.HasPrefix(target.CfName, "#") {
continue continue
} }
_, seq, err := client.server.GetHistorySequence(nil, client, target.CfName, 0) _, seq, err := client.server.GetHistorySequence(nil, client, target.CfName)
if err == nil && seq != nil { if err == nil && seq != nil {
items, err := seq.Between(start, end, messageLimit) items, err := seq.Between(start, end, messageLimit)
if err == nil { if err == nil {

View File

@ -24,7 +24,7 @@ const (
// 'version' of the database schema // 'version' of the database schema
keySchemaVersion = "db.version" keySchemaVersion = "db.version"
// latest schema of the db // latest schema of the db
latestDbSchema = 21 latestDbSchema = 22
keyCloakSecret = "crypto.cloak_secret" keyCloakSecret = "crypto.cloak_secret"
) )
@ -1059,6 +1059,56 @@ func schemaChangeV20To21(config *Config, tx *buntdb.Tx) error {
return nil return nil
} }
// #1676: we used to have ReplayJoinsNever, now it's desupported
func schemaChangeV21To22(config *Config, tx *buntdb.Tx) error {
type accountSettingsv22 struct {
AutoreplayLines *int
NickEnforcement NickEnforcementMethod
AllowBouncer MulticlientAllowedSetting
ReplayJoins ReplayJoinsSetting
AlwaysOn PersistentStatus
AutoreplayMissed bool
DMHistory HistoryStatus
AutoAway PersistentStatus
Email string
}
var accounts []string
var serializedSettings []string
settingsPrefix := "account.settings "
tx.AscendGreaterOrEqual("", settingsPrefix, func(key, value string) bool {
if !strings.HasPrefix(key, settingsPrefix) {
return false
}
account := strings.TrimPrefix(key, settingsPrefix)
if _, err := tx.Get("account.verified " + account); err != nil {
return true
}
var settings accountSettingsv22
err := json.Unmarshal([]byte(value), &settings)
if err != nil {
log.Printf("error (v21-22) processing settings for %s: %v\n", account, err)
return true
}
// if necessary, change ReplayJoinsNever (2) to ReplayJoinsCommandsOnly (0)
if settings.ReplayJoins == ReplayJoinsSetting(2) {
settings.ReplayJoins = ReplayJoinsSetting(0)
if b, err := json.Marshal(settings); err == nil {
accounts = append(accounts, account)
serializedSettings = append(serializedSettings, string(b))
} else {
log.Printf("error (v21-22) processing settings for %s: %v\n", account, err)
}
}
return true
})
for i, account := range accounts {
tx.Set(settingsPrefix+account, serializedSettings[i], nil)
}
return nil
}
func getSchemaChange(initialVersion int) (result SchemaChange, ok bool) { func getSchemaChange(initialVersion int) (result SchemaChange, ok bool) {
for _, change := range allChanges { for _, change := range allChanges {
if initialVersion == change.InitialVersion { if initialVersion == change.InitialVersion {
@ -1169,4 +1219,9 @@ var allChanges = []SchemaChange{
TargetVersion: 21, TargetVersion: 21,
Changer: schemaChangeV20To21, Changer: schemaChangeV20To21,
}, },
{
InitialVersion: 21,
TargetVersion: 22,
Changer: schemaChangeV21To22,
},
} }

View File

@ -611,9 +611,9 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
target.Time.Format(IRCv3TimestampFormat)) target.Time.Format(IRCv3TimestampFormat))
} }
} else if channel != nil { } else if channel != nil {
channel.replayHistoryItems(rb, items, false) channel.replayHistoryItems(rb, items, true)
} else { } else {
client.replayPrivmsgHistory(rb, items, target) client.replayPrivmsgHistory(rb, items, target, true)
} }
} }
}() }()
@ -725,17 +725,7 @@ func chathistoryHandler(server *Server, client *Client, msg ircmsg.Message, rb *
if listTargets { if listTargets {
targets, err = client.listTargets(start, end, limit) targets, err = client.listTargets(start, end, limit)
} else { } else {
// see #1676; for CHATHISTORY we need to make the paging window as exact as possible, channel, sequence, err = server.GetHistorySequence(nil, client, target)
// hence filtering out undisplayable messages on the backend, in order to send a full
// paging window if possible
var flags history.ExcludeFlags
if !rb.session.capabilities.Has(caps.EventPlayback) {
flags |= history.ExcludeTagmsg
}
if client.AccountSettings().ReplayJoins == ReplayJoinsNever {
flags |= history.ExcludeJoins
}
channel, sequence, err = server.GetHistorySequence(nil, client, target, flags)
if err != nil || sequence == nil { if err != nil || sequence == nil {
return return
} }
@ -1132,9 +1122,9 @@ func historyHandler(server *Server, client *Client, msg ircmsg.Message, rb *Resp
if len(items) != 0 { if len(items) != 0 {
if channel != nil { if channel != nil {
channel.replayHistoryItems(rb, items, false) channel.replayHistoryItems(rb, items, true)
} else { } else {
client.replayPrivmsgHistory(rb, items, "") client.replayPrivmsgHistory(rb, items, "", true)
} }
} }
return false return false

View File

@ -53,17 +53,6 @@ func (item *Item) HasMsgid(msgid string) bool {
return item.Message.Msgid == msgid return item.Message.Msgid == msgid
} }
func (item *Item) IsExcluded(excludeFlags ExcludeFlags) bool {
switch item.Type {
case Tagmsg:
return excludeFlags&ExcludeTagmsg != 0
case Join, Part, Quit:
return excludeFlags&ExcludeJoins != 0
default:
return false
}
}
type Predicate func(item *Item) (matches bool) type Predicate func(item *Item) (matches bool)
func Reverse(results []Item) { func Reverse(results []Item) {
@ -166,7 +155,7 @@ func (list *Buffer) lookup(msgid string) (result Item, found bool) {
// with an indication of whether the results are complete or are missing items // with an indication of whether the results are complete or are missing items
// because some of that period was discarded. A zero value of `before` is considered // because some of that period was discarded. A zero value of `before` is considered
// higher than all other times. // higher than all other times.
func (list *Buffer) betweenHelper(start, end Selector, cutoff time.Time, pred Predicate, limit int, excludeFlags ExcludeFlags) (results []Item, complete bool, err error) { func (list *Buffer) betweenHelper(start, end Selector, cutoff time.Time, pred Predicate, limit int) (results []Item, complete bool, err error) {
var ascending bool var ascending bool
defer func() { defer func() {
@ -206,8 +195,7 @@ func (list *Buffer) betweenHelper(start, end Selector, cutoff time.Time, pred Pr
satisfies := func(item *Item) bool { satisfies := func(item *Item) bool {
return (after.IsZero() || item.Message.Time.After(after)) && return (after.IsZero() || item.Message.Time.After(after)) &&
(before.IsZero() || item.Message.Time.Before(before)) && (before.IsZero() || item.Message.Time.Before(before)) &&
(pred == nil || pred(item)) && (pred == nil || pred(item))
!item.IsExcluded(excludeFlags)
} }
return list.matchInternal(satisfies, ascending, limit), complete, nil return list.matchInternal(satisfies, ascending, limit), complete, nil
@ -291,10 +279,9 @@ type bufferSequence struct {
list *Buffer list *Buffer
pred Predicate pred Predicate
cutoff time.Time cutoff time.Time
flags ExcludeFlags
} }
func (list *Buffer) MakeSequence(correspondent string, cutoff time.Time, flags ExcludeFlags) Sequence { func (list *Buffer) MakeSequence(correspondent string, cutoff time.Time) Sequence {
var pred Predicate var pred Predicate
if correspondent != "" { if correspondent != "" {
pred = func(item *Item) bool { pred = func(item *Item) bool {
@ -305,12 +292,11 @@ func (list *Buffer) MakeSequence(correspondent string, cutoff time.Time, flags E
list: list, list: list,
pred: pred, pred: pred,
cutoff: cutoff, cutoff: cutoff,
flags: flags,
} }
} }
func (seq *bufferSequence) Between(start, end Selector, limit int) (results []Item, err error) { func (seq *bufferSequence) Between(start, end Selector, limit int) (results []Item, err error) {
results, _, err = seq.list.betweenHelper(start, end, seq.cutoff, seq.pred, limit, seq.flags) results, _, err = seq.list.betweenHelper(start, end, seq.cutoff, seq.pred, limit)
return return
} }
@ -391,7 +377,7 @@ func (list *Buffer) Delete(predicate Predicate) (count int) {
// latest returns the items most recently added, up to `limit`. If `limit` is 0, // latest returns the items most recently added, up to `limit`. If `limit` is 0,
// it returns all items. // it returns all items.
func (list *Buffer) latest(limit int) (results []Item) { func (list *Buffer) latest(limit int) (results []Item) {
results, _, _ = list.betweenHelper(Selector{}, Selector{}, time.Time{}, nil, limit, 0) results, _, _ = list.betweenHelper(Selector{}, Selector{}, time.Time{}, nil, limit)
return return
} }

View File

@ -15,7 +15,7 @@ const (
) )
func betweenTimestamps(buf *Buffer, start, end time.Time, limit int) (result []Item, complete bool) { func betweenTimestamps(buf *Buffer, start, end time.Time, limit int) (result []Item, complete bool) {
result, complete, _ = buf.betweenHelper(Selector{Time: start}, Selector{Time: end}, time.Time{}, nil, limit, 0) result, complete, _ = buf.betweenHelper(Selector{Time: start}, Selector{Time: end}, time.Time{}, nil, limit)
return return
} }
@ -45,7 +45,7 @@ func TestEmptyBuffer(t *testing.T) {
}) })
since, complete = betweenTimestamps(buf, pastTime, time.Now(), 0) since, complete = betweenTimestamps(buf, pastTime, time.Now(), 0)
if len(since) != 1 { if len(since) != 1 {
t.Errorf("should be able to store items in a nonempty buffer: expected %d, got %d", 1, len(since)) t.Error("should be able to store items in a nonempty buffer")
} }
if !complete { if !complete {
t.Error("results should be complete") t.Error("results should be complete")

View File

@ -8,13 +8,6 @@ import (
"time" "time"
) )
type ExcludeFlags uint
const (
ExcludeTagmsg ExcludeFlags = 1 << iota
ExcludeJoins
)
// Selector represents a parameter to a CHATHISTORY command // Selector represents a parameter to a CHATHISTORY command
type Selector struct { type Selector struct {
Msgid string Msgid string

View File

@ -199,7 +199,7 @@ func histservPlayHandler(service *ircService, server *Server, client *Client, co
// handles parameter parsing and history queries for /HISTORY and /HISTSERV PLAY // handles parameter parsing and history queries for /HISTORY and /HISTSERV PLAY
func easySelectHistory(server *Server, client *Client, params []string) (items []history.Item, channel *Channel, err error) { func easySelectHistory(server *Server, client *Client, params []string) (items []history.Item, channel *Channel, err error) {
channel, sequence, err := server.GetHistorySequence(nil, client, params[0], 0) channel, sequence, err := server.GetHistorySequence(nil, client, params[0])
if sequence == nil || err != nil { if sequence == nil || err != nil {
return nil, nil, errNoSuchChannel return nil, nil, errNoSuchChannel

View File

@ -40,10 +40,6 @@ const (
keySchemaMinorVersion = "db.minorversion" keySchemaMinorVersion = "db.minorversion"
cleanupRowLimit = 50 cleanupRowLimit = 50
cleanupPauseTime = 10 * time.Minute cleanupPauseTime = 10 * time.Minute
// if we don't fill the pagination window due to exclusions,
// retry with an expanded window at most this many times
maxPaginationRetries = 3
) )
type e struct{} type e struct{}
@ -1037,18 +1033,9 @@ type mySQLHistorySequence struct {
target string target string
correspondent string correspondent string
cutoff time.Time cutoff time.Time
excludeFlags history.ExcludeFlags
} }
func (s *mySQLHistorySequence) Between(start, end history.Selector, limit int) (results []history.Item, err error) { func (s *mySQLHistorySequence) Between(start, end history.Selector, limit int) (results []history.Item, err error) {
if s.excludeFlags == 0 {
return s.baseBetween(start, end, limit)
} else {
return s.betweenWithRetries(start, end, limit)
}
}
func (s *mySQLHistorySequence) baseBetween(start, end history.Selector, limit int) (results []history.Item, err error) {
ctx, cancel := context.WithTimeout(context.Background(), s.mysql.getTimeout()) ctx, cancel := context.WithTimeout(context.Background(), s.mysql.getTimeout())
defer cancel() defer cancel()
@ -1071,45 +1058,7 @@ func (s *mySQLHistorySequence) baseBetween(start, end history.Selector, limit in
return results, err return results, err
} }
func (s *mySQLHistorySequence) betweenWithRetries(start, end history.Selector, limit int) (results []history.Item, err error) {
applyExclusions := func(currentResults []history.Item, excludeFlags history.ExcludeFlags, trueLimit int) (filteredResults []history.Item) {
filteredResults = make([]history.Item, 0, len(currentResults))
for _, item := range currentResults {
if !item.IsExcluded(excludeFlags) {
filteredResults = append(filteredResults, item)
}
if len(filteredResults) == trueLimit {
break
}
}
return
}
i := 1
for {
currentLimit := limit * i
currentResults, err := s.baseBetween(start, end, currentLimit)
if err != nil {
return nil, err
}
results = applyExclusions(currentResults, s.excludeFlags, limit)
// we're done in any of these three cases:
// (1) we filled the window (2) we ran out of results on the backend (3) we can't retry anymore
if len(results) == limit || len(currentResults) < currentLimit || i == maxPaginationRetries {
return results, nil
}
i++
}
}
func (s *mySQLHistorySequence) Around(start history.Selector, limit int) (results []history.Item, err error) { func (s *mySQLHistorySequence) Around(start history.Selector, limit int) (results []history.Item, err error) {
// temporarily clear the exclude flags when running GenericAround, since we don't care about
// the exactness of the paging window at all
oldExcludeFlags := s.excludeFlags
s.excludeFlags = 0
defer func() {
s.excludeFlags = oldExcludeFlags
}()
return history.GenericAround(s, start, limit) return history.GenericAround(s, start, limit)
} }
@ -1134,12 +1083,11 @@ func (seq *mySQLHistorySequence) Ephemeral() bool {
return false return false
} }
func (mysql *MySQL) MakeSequence(target, correspondent string, cutoff time.Time, excludeFlags history.ExcludeFlags) history.Sequence { func (mysql *MySQL) MakeSequence(target, correspondent string, cutoff time.Time) history.Sequence {
return &mySQLHistorySequence{ return &mySQLHistorySequence{
target: target, target: target,
correspondent: correspondent, correspondent: correspondent,
mysql: mysql, mysql: mysql,
cutoff: cutoff, cutoff: cutoff,
excludeFlags: excludeFlags,
} }
} }

View File

@ -284,8 +284,8 @@ default.`,
`$bREPLAY-JOINS$b `$bREPLAY-JOINS$b
'replay-joins' controls whether replayed channel history will include 'replay-joins' controls whether replayed channel history will include
lines for join and part. This provides more information about the context of lines for join and part. This provides more information about the context of
messages, but may be spammy. Your options are 'always', 'never', and the default messages, but may be spammy. Your options are 'always' and the default of
of 'commands-only' (the messages will be replayed in /HISTORY output, but not 'commands-only' (the messages will be replayed in CHATHISTORY output, but not
during autoreplay).`, during autoreplay).`,
`$bALWAYS-ON$b `$bALWAYS-ON$b
'always-on' controls whether your nickname/identity will remain active 'always-on' controls whether your nickname/identity will remain active
@ -440,8 +440,6 @@ func displaySetting(service *ircService, settingName string, settings AccountSet
service.Notice(rb, client.t("You will see JOINs and PARTs in /HISTORY output, but not in autoreplay")) service.Notice(rb, client.t("You will see JOINs and PARTs in /HISTORY output, but not in autoreplay"))
case ReplayJoinsAlways: case ReplayJoinsAlways:
service.Notice(rb, client.t("You will see JOINs and PARTs in /HISTORY output and in autoreplay")) service.Notice(rb, client.t("You will see JOINs and PARTs in /HISTORY output and in autoreplay"))
case ReplayJoinsNever:
service.Notice(rb, client.t("You will not see JOINs and PARTs in /HISTORY output or in autoreplay"))
} }
case "multiclient": case "multiclient":
if !config.Accounts.Multiclient.Enabled { if !config.Accounts.Multiclient.Enabled {

View File

@ -868,7 +868,7 @@ func (server *Server) setupListeners(config *Config) (err error) {
// suitable for ListCorrespondents (i.e., this function is still used to // suitable for ListCorrespondents (i.e., this function is still used to
// decide whether the ringbuf or mysql is authoritative about the client's // decide whether the ringbuf or mysql is authoritative about the client's
// message history). // message history).
func (server *Server) GetHistorySequence(providedChannel *Channel, client *Client, query string, excludeFlags history.ExcludeFlags) (channel *Channel, sequence history.Sequence, err error) { func (server *Server) GetHistorySequence(providedChannel *Channel, client *Client, query string) (channel *Channel, sequence history.Sequence, err error) {
config := server.Config() config := server.Config()
// 4 cases: {persistent, ephemeral} x {normal, conversation} // 4 cases: {persistent, ephemeral} x {normal, conversation}
// with ephemeral history, target is implicit in the choice of `hist`, // with ephemeral history, target is implicit in the choice of `hist`,
@ -946,9 +946,9 @@ func (server *Server) GetHistorySequence(providedChannel *Channel, client *Clien
} }
if hist != nil { if hist != nil {
sequence = hist.MakeSequence(correspondent, cutoff, excludeFlags) sequence = hist.MakeSequence(correspondent, cutoff)
} else if target != "" { } else if target != "" {
sequence = server.historyDB.MakeSequence(target, correspondent, cutoff, excludeFlags) sequence = server.historyDB.MakeSequence(target, correspondent, cutoff)
} }
return return
} }

View File

@ -189,14 +189,14 @@ func zncPlaybackPlayHandler(client *Client, command string, params []string, rb
} }
func zncPlayPrivmsgsFrom(client *Client, rb *ResponseBuffer, target string, start, end time.Time) { func zncPlayPrivmsgsFrom(client *Client, rb *ResponseBuffer, target string, start, end time.Time) {
_, sequence, err := client.server.GetHistorySequence(nil, client, target, 0) _, sequence, err := client.server.GetHistorySequence(nil, client, target)
if sequence == nil || err != nil { if sequence == nil || err != nil {
return return
} }
zncMax := client.server.Config().History.ZNCMax zncMax := client.server.Config().History.ZNCMax
items, err := sequence.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax) items, err := sequence.Between(history.Selector{Time: start}, history.Selector{Time: end}, zncMax)
if err == nil && len(items) != 0 { if err == nil && len(items) != 0 {
client.replayPrivmsgHistory(rb, items, target) client.replayPrivmsgHistory(rb, items, target, false)
} }
} }
@ -204,7 +204,7 @@ func zncPlayPrivmsgsFromAll(client *Client, rb *ResponseBuffer, start, end time.
zncMax := client.server.Config().History.ZNCMax zncMax := client.server.Config().History.ZNCMax
items, err := client.privmsgsBetween(start, end, maxDMTargetsForAutoplay, zncMax) items, err := client.privmsgsBetween(start, end, maxDMTargetsForAutoplay, zncMax)
if err == nil && len(items) != 0 { if err == nil && len(items) != 0 {
client.replayPrivmsgHistory(rb, items, "") client.replayPrivmsgHistory(rb, items, "", false)
} }
} }

@ -1 +1 @@
Subproject commit 33f0702c260ea716a4ad0f24821a50d44c91fca1 Subproject commit 5e4ae7c99965801cd91d974637ad344a47b5414f

View File

@ -939,7 +939,7 @@ history:
# if `default` is false, store TAGMSG containing any of these tags: # if `default` is false, store TAGMSG containing any of these tags:
whitelist: whitelist:
- "+draft/react" - "+draft/react"
- "react" - "+react"
# if `default` is true, don't store TAGMSG containing any of these tags: # if `default` is true, don't store TAGMSG containing any of these tags:
#blacklist: #blacklist: