3
0
mirror of https://github.com/ergochat/ergo.git synced 2024-12-29 14:12:38 +01:00
ergo/irc/responsebuffer.go
2018-11-26 05:23:27 -05:00

140 lines
4.1 KiB
Go

// Copyright (c) 2016-2017 Daniel Oaks <daniel@danieloaks.net>
// released under the MIT license
package irc
import (
"time"
"github.com/goshuirc/irc-go/ircmsg"
"github.com/oragono/oragono/irc/caps"
"github.com/oragono/oragono/irc/utils"
)
// ResponseBuffer - put simply - buffers messages and then outputs them to a given client.
//
// Using a ResponseBuffer lets you really easily implement labeled-response, since the
// buffer will silently create a batch if required and label the outgoing messages as
// necessary (or leave it off and simply tag the outgoing message).
type ResponseBuffer struct {
Label string
target *Client
messages []ircmsg.IrcMessage
blocking bool
}
// GetLabel returns the label from the given message.
func GetLabel(msg ircmsg.IrcMessage) string {
return msg.Tags[caps.LabelTagName].Value
}
// NewResponseBuffer returns a new ResponseBuffer.
func NewResponseBuffer(target *Client) *ResponseBuffer {
return &ResponseBuffer{
target: target,
}
}
func (rb *ResponseBuffer) SetBlocking(blocking bool) {
rb.blocking = blocking
}
// Add adds a standard new message to our queue.
func (rb *ResponseBuffer) Add(tags *map[string]ircmsg.TagValue, prefix string, command string, params ...string) {
message := ircmsg.MakeMessage(tags, prefix, command, params...)
rb.messages = append(rb.messages, message)
}
// AddFromClient adds a new message from a specific client to our queue.
func (rb *ResponseBuffer) AddFromClient(msgid string, from *Client, tags *map[string]ircmsg.TagValue, command string, params ...string) {
// attach account-tag
if rb.target.capabilities.Has(caps.AccountTag) && from.LoggedIntoAccount() {
if tags == nil {
tags = ircmsg.MakeTags("account", from.AccountName())
} else {
(*tags)["account"] = ircmsg.MakeTagValue(from.AccountName())
}
}
// attach message-id
if len(msgid) > 0 && rb.target.capabilities.Has(caps.MessageTags) {
if tags == nil {
tags = ircmsg.MakeTags("draft/msgid", msgid)
} else {
(*tags)["draft/msgid"] = ircmsg.MakeTagValue(msgid)
}
}
rb.Add(tags, from.nickMaskString, command, params...)
}
// AddSplitMessageFromClient adds a new split message from a specific client to our queue.
func (rb *ResponseBuffer) AddSplitMessageFromClient(msgid string, from *Client, tags *map[string]ircmsg.TagValue, command string, target string, message utils.SplitMessage) {
if rb.target.capabilities.Has(caps.MaxLine) || message.Wrapped == nil {
rb.AddFromClient(msgid, from, tags, command, target, message.Original)
} else {
for _, str := range message.Wrapped {
rb.AddFromClient(msgid, from, tags, command, target, str)
}
}
}
// Send sends the message to our target client.
func (rb *ResponseBuffer) Send() error {
// fall out if no messages to send
if len(rb.messages) == 0 {
return nil
}
// make batch and all if required
var batch *Batch
useLabel := rb.target.capabilities.Has(caps.LabeledResponse) && rb.Label != ""
if useLabel && 1 < len(rb.messages) && rb.target.capabilities.Has(caps.Batch) {
batch = rb.target.server.batches.New("draft/labeled-response")
}
// if label but no batch, add label to first message
if useLabel && batch == nil {
message := rb.messages[0]
message.Tags[caps.LabelTagName] = ircmsg.MakeTagValue(rb.Label)
rb.messages[0] = message
}
// start batch if required
if batch != nil {
batch.Start(rb.target, ircmsg.MakeTags(caps.LabelTagName, rb.Label))
}
// send each message out
for _, message := range rb.messages {
// attach server-time if needed
if rb.target.capabilities.Has(caps.ServerTime) {
t := time.Now().UTC().Format(IRCv3TimestampFormat)
message.Tags["time"] = ircmsg.MakeTagValue(t)
}
// attach batch ID
if batch != nil {
message.Tags["batch"] = ircmsg.MakeTagValue(batch.ID)
}
// send message out
rb.target.SendRawMessage(message, rb.blocking)
}
// end batch if required
if batch != nil {
batch.End(rb.target)
}
// clear out any existing messages
rb.messages = rb.messages[:0]
return nil
}
// Notice sends the client the given notice from the server.
func (rb *ResponseBuffer) Notice(text string) {
rb.Add(nil, rb.target.server.name, "NOTICE", rb.target.nick, text)
}