mirror of
https://github.com/ergochat/ergo.git
synced 2024-11-26 22:09:24 +01:00
commit
e551002944
@ -813,16 +813,19 @@ func (channel *Channel) autoReplayHistory(client *Client, rb *ResponseBuffer, sk
|
|||||||
// autoreplay any messages as necessary
|
// autoreplay any messages as necessary
|
||||||
var items []history.Item
|
var items []history.Item
|
||||||
|
|
||||||
|
hasAutoreplayTimestamps := false
|
||||||
var start, end time.Time
|
var start, end time.Time
|
||||||
if rb.session.zncPlaybackTimes.ValidFor(channel.NameCasefolded()) {
|
if rb.session.zncPlaybackTimes.ValidFor(channel.NameCasefolded()) {
|
||||||
|
hasAutoreplayTimestamps = true
|
||||||
start, end = rb.session.zncPlaybackTimes.start, rb.session.zncPlaybackTimes.end
|
start, end = rb.session.zncPlaybackTimes.start, rb.session.zncPlaybackTimes.end
|
||||||
} else if !rb.session.autoreplayMissedSince.IsZero() {
|
} else if !rb.session.autoreplayMissedSince.IsZero() {
|
||||||
// we already checked for history caps in `playReattachMessages`
|
// we already checked for history caps in `playReattachMessages`
|
||||||
|
hasAutoreplayTimestamps = true
|
||||||
start = time.Now().UTC()
|
start = time.Now().UTC()
|
||||||
end = rb.session.autoreplayMissedSince
|
end = rb.session.autoreplayMissedSince
|
||||||
}
|
}
|
||||||
|
|
||||||
if !start.IsZero() || !end.IsZero() {
|
if hasAutoreplayTimestamps {
|
||||||
_, seq, _ := channel.server.GetHistorySequence(channel, client, "")
|
_, seq, _ := channel.server.GetHistorySequence(channel, client, "")
|
||||||
if seq != nil {
|
if seq != nil {
|
||||||
zncMax := channel.server.Config().History.ZNCMax
|
zncMax := channel.server.Config().History.ZNCMax
|
||||||
|
@ -3131,7 +3131,12 @@ func whowasHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *Re
|
|||||||
|
|
||||||
// ZNC <module> [params]
|
// ZNC <module> [params]
|
||||||
func zncHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
func zncHandler(server *Server, client *Client, msg ircmsg.IrcMessage, rb *ResponseBuffer) bool {
|
||||||
zncModuleHandler(client, msg.Params[0], msg.Params[1:], rb)
|
params := msg.Params[1:]
|
||||||
|
// #1205: compatibility with Palaver, which sends `ZNC *playback :play ...`
|
||||||
|
if len(params) == 1 && strings.IndexByte(params[0], ' ') != -1 {
|
||||||
|
params = strings.Fields(params[0])
|
||||||
|
}
|
||||||
|
zncModuleHandler(client, msg.Params[0], params, rb)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,8 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Selector represents a parameter to a CHATHISTORY command;
|
// Selector represents a parameter to a CHATHISTORY command
|
||||||
// at most one of Msgid or Time may be nonzero
|
|
||||||
type Selector struct {
|
type Selector struct {
|
||||||
Msgid string
|
Msgid string
|
||||||
Time time.Time
|
Time time.Time
|
||||||
|
@ -25,7 +25,7 @@ const (
|
|||||||
type ResponseBuffer struct {
|
type ResponseBuffer struct {
|
||||||
Label string // label if this is a labeled response batch
|
Label string // label if this is a labeled response batch
|
||||||
batchID string // ID of the labeled response batch, if one has been initiated
|
batchID string // ID of the labeled response batch, if one has been initiated
|
||||||
batchType string // type of the labeled response batch (possibly `history` or `chathistory`)
|
batchType string // type of the labeled response batch (currently either `labeled-response` or `chathistory`)
|
||||||
|
|
||||||
// stack of batch IDs of nested batches, which are handled separately
|
// stack of batch IDs of nested batches, which are handled separately
|
||||||
// from the underlying labeled-response batch. starting a new nested batch
|
// from the underlying labeled-response batch. starting a new nested batch
|
||||||
@ -200,9 +200,7 @@ func (rb *ResponseBuffer) EndNestedBatch(batchID string) {
|
|||||||
// supported by the client (`history`, `chathistory`, or no batch, in descending order).
|
// supported by the client (`history`, `chathistory`, or no batch, in descending order).
|
||||||
func (rb *ResponseBuffer) StartNestedHistoryBatch(params ...string) (batchID string) {
|
func (rb *ResponseBuffer) StartNestedHistoryBatch(params ...string) (batchID string) {
|
||||||
var batchType string
|
var batchType string
|
||||||
if rb.session.capabilities.Has(caps.EventPlayback) {
|
if rb.session.capabilities.Has(caps.Batch) {
|
||||||
batchType = "history"
|
|
||||||
} else if rb.session.capabilities.Has(caps.Batch) {
|
|
||||||
batchType = "chathistory"
|
batchType = "chathistory"
|
||||||
}
|
}
|
||||||
if batchType != "" {
|
if batchType != "" {
|
||||||
|
56
irc/znc.go
56
irc/znc.go
@ -53,6 +53,12 @@ func zncWireTimeToTime(str string) (result time.Time) {
|
|||||||
return time.Unix(seconds, int64(fraction*1000000000)).UTC()
|
return time.Unix(seconds, int64(fraction*1000000000)).UTC()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func timeToZncWireTime(t time.Time) (result string) {
|
||||||
|
secs := t.Unix()
|
||||||
|
nano := t.UnixNano() - (secs * 1000000000)
|
||||||
|
return fmt.Sprintf("%d.%d", secs, nano)
|
||||||
|
}
|
||||||
|
|
||||||
type zncPlaybackTimes struct {
|
type zncPlaybackTimes struct {
|
||||||
start time.Time
|
start time.Time
|
||||||
end time.Time
|
end time.Time
|
||||||
@ -77,19 +83,33 @@ func (z *zncPlaybackTimes) ValidFor(target string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://wiki.znc.in/Playback
|
// https://wiki.znc.in/Playback
|
||||||
|
func zncPlaybackHandler(client *Client, command string, params []string, rb *ResponseBuffer) {
|
||||||
|
if len(params) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch strings.ToLower(params[0]) {
|
||||||
|
case "play":
|
||||||
|
zncPlaybackPlayHandler(client, command, params, rb)
|
||||||
|
case "list":
|
||||||
|
zncPlaybackListHandler(client, command, params, rb)
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// PRIVMSG *playback :play <target> [lower_bound] [upper_bound]
|
// PRIVMSG *playback :play <target> [lower_bound] [upper_bound]
|
||||||
// e.g., PRIVMSG *playback :play * 1558374442
|
// e.g., PRIVMSG *playback :play * 1558374442
|
||||||
func zncPlaybackHandler(client *Client, command string, params []string, rb *ResponseBuffer) {
|
func zncPlaybackPlayHandler(client *Client, command string, params []string, rb *ResponseBuffer) {
|
||||||
if len(params) < 2 || len(params) > 4 {
|
if len(params) < 2 || len(params) > 4 {
|
||||||
return
|
return
|
||||||
} else if strings.ToLower(params[0]) != "play" {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
targetString := params[1]
|
targetString := params[1]
|
||||||
|
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
var start, end time.Time
|
var start, end time.Time
|
||||||
switch len(params) {
|
switch len(params) {
|
||||||
|
case 2:
|
||||||
|
// #1205: this should have the same semantics as `LATEST *`
|
||||||
case 3:
|
case 3:
|
||||||
// #831: this should have the same semantics as `LATEST timestamp=qux`,
|
// #831: this should have the same semantics as `LATEST timestamp=qux`,
|
||||||
// or equivalently `BETWEEN timestamp=$now timestamp=qux`, as opposed to
|
// or equivalently `BETWEEN timestamp=$now timestamp=qux`, as opposed to
|
||||||
@ -121,12 +141,15 @@ func zncPlaybackHandler(client *Client, command string, params []string, rb *Res
|
|||||||
// 3.3 When the client sends a subsequent redundant JOIN line for those
|
// 3.3 When the client sends a subsequent redundant JOIN line for those
|
||||||
// channels; redundant JOIN is a complete no-op so we won't replay twice
|
// channels; redundant JOIN is a complete no-op so we won't replay twice
|
||||||
|
|
||||||
|
playPrivmsgs := false
|
||||||
if params[1] == "*" {
|
if params[1] == "*" {
|
||||||
zncPlayPrivmsgs(client, rb, "*", start, end)
|
playPrivmsgs = true // XXX nil `targets` means "every channel"
|
||||||
} else {
|
} else {
|
||||||
targets = make(StringSet)
|
targets = make(StringSet)
|
||||||
for _, targetName := range strings.Split(targetString, ",") {
|
for _, targetName := range strings.Split(targetString, ",") {
|
||||||
if strings.HasPrefix(targetName, "#") {
|
if targetName == "*self" {
|
||||||
|
playPrivmsgs = true
|
||||||
|
} else if strings.HasPrefix(targetName, "#") {
|
||||||
if cfTarget, err := CasefoldChannel(targetName); err == nil {
|
if cfTarget, err := CasefoldChannel(targetName); err == nil {
|
||||||
targets.Add(cfTarget)
|
targets.Add(cfTarget)
|
||||||
}
|
}
|
||||||
@ -138,6 +161,10 @@ func zncPlaybackHandler(client *Client, command string, params []string, rb *Res
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if playPrivmsgs {
|
||||||
|
zncPlayPrivmsgs(client, rb, "*", start, end)
|
||||||
|
}
|
||||||
|
|
||||||
rb.session.zncPlaybackTimes = &zncPlaybackTimes{
|
rb.session.zncPlaybackTimes = &zncPlaybackTimes{
|
||||||
start: start,
|
start: start,
|
||||||
end: end,
|
end: end,
|
||||||
@ -169,3 +196,22 @@ func zncPlayPrivmsgs(client *Client, rb *ResponseBuffer, target string, after, b
|
|||||||
client.replayPrivmsgHistory(rb, items, "", true)
|
client.replayPrivmsgHistory(rb, items, "", true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// PRIVMSG *playback :list
|
||||||
|
func zncPlaybackListHandler(client *Client, command string, params []string, rb *ResponseBuffer) {
|
||||||
|
nick := client.Nick()
|
||||||
|
for _, channel := range client.Channels() {
|
||||||
|
_, sequence, err := client.server.GetHistorySequence(channel, client, "")
|
||||||
|
if err != nil {
|
||||||
|
client.server.logger.Error("internal", "couldn't get history sequence for ZNC list", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
items, _, err := sequence.Between(history.Selector{}, history.Selector{}, 1) // i.e., LATEST * 1
|
||||||
|
if err != nil {
|
||||||
|
client.server.logger.Error("internal", "couldn't query history for ZNC list", err.Error())
|
||||||
|
} else if len(items) != 0 {
|
||||||
|
stamp := timeToZncWireTime(items[0].Message.Time)
|
||||||
|
rb.Add(nil, "*playback!znc@znc.in", "PRIVMSG", nick, fmt.Sprintf("%s 0 %s", channel.Name(), stamp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user