rename to Message and Reader; remove Event

This commit is contained in:
Shivaram Lingamneni 2021-03-10 17:58:53 -05:00
parent 4d7631f681
commit 23a3bb8f66
17 changed files with 164 additions and 188 deletions

View File

@ -23,12 +23,12 @@ irc := ircevent.Connection{
RequestCaps: []string{"server-time", "message-tags"},
}
irc.AddCallback("001", func(e ircevent.Event) { irc.Join("#ircevent-test") })
irc.AddCallback("001", func(e ircmsg.Message) { irc.Join("#ircevent-test") })
irc.AddCallback("PRIVMSG", func(event ircevent.Event) {
//event.Message() contains the message
//event.Nick() Contains the sender
//event.Params[0] Contains the channel
irc.AddCallback("PRIVMSG", func(event ircmsg.Message) {
// event.Prefix is the source;
// event.Params[0] is the target (the channel or nickname the message was sent to)
// and event.Params[1] is the message itself
});
err := irc.Connect()

View File

@ -8,6 +8,7 @@ import (
"strings"
"github.com/goshuirc/irc-go/ircevent"
"github.com/goshuirc/irc-go/ircmsg"
)
func getenv(key, defaultValue string) (value string) {
@ -36,15 +37,15 @@ func main() {
SASLPassword: saslPassword,
}
irc.AddConnectCallback(func(e ircevent.Event) {
irc.AddConnectCallback(func(e ircmsg.Message) {
// attempt to set the BOT mode on ourself:
if botMode := irc.ISupport()["BOT"]; botMode != "" {
irc.Send("MODE", irc.CurrentNick(), "+"+botMode)
}
irc.Join(channel)
})
irc.AddCallback("JOIN", func(e ircevent.Event) {}) // TODO try to rejoin if we *don't* get this
irc.AddCallback("PRIVMSG", func(e ircevent.Event) {
irc.AddCallback("JOIN", func(e ircmsg.Message) {}) // TODO try to rejoin if we *don't* get this
irc.AddCallback("PRIVMSG", func(e ircmsg.Message) {
if len(e.Params) < 2 {
return
}
@ -65,7 +66,7 @@ func main() {
// example client-to-client extension via message-tags:
// have the bot maintain a running sum of integers
var sum int64 // doesn't need synchronization as long as it's only visible from a single callback
irc.AddCallback("TAGMSG", func(e ircevent.Event) {
irc.AddCallback("TAGMSG", func(e ircmsg.Message) {
_, tv := e.GetTag("+summand")
if v, err := strconv.ParseInt(tv, 10, 64); err == nil {
sum += v

View File

@ -9,6 +9,7 @@ import (
_ "net/http/pprof"
"github.com/goshuirc/irc-go/ircevent"
"github.com/goshuirc/irc-go/ircmsg"
)
/*
@ -48,11 +49,11 @@ func main() {
RequestCaps: []string{"server-time", "echo-message"},
}
irc.AddCallback("001", func(e ircevent.Event) { irc.Join(channel) })
irc.AddCallback("JOIN", func(e ircevent.Event) { irc.Privmsg(channel, "hi there friend!") })
irc.AddCallback("001", func(e ircmsg.Message) { irc.Join(channel) })
irc.AddCallback("JOIN", func(e ircmsg.Message) { irc.Privmsg(channel, "hi there friend!") })
// echo whatever we get back
count := 0
irc.AddCallback("PRIVMSG", func(e ircevent.Event) {
irc.AddCallback("PRIVMSG", func(e ircmsg.Message) {
if limit != 0 && count >= limit {
irc.Quit()
} else {

View File

@ -142,7 +142,7 @@ func (irc *Connection) readLoop() {
}
func readMsgLoop(socket net.Conn, maxLineLen int, msgChan chan string, errChan chan error, end chan empty) {
var reader ircreader.IRCReader
var reader ircreader.Reader
reader.Initialize(socket, 1024, maxLineLen+maxlenTags)
for {
msgBytes, err := reader.ReadLine()
@ -348,8 +348,8 @@ func (irc *Connection) sendInternal(b []byte) (err error) {
}
}
// Send a built ircmsg.IRCMessage.
func (irc *Connection) SendIRCMessage(msg ircmsg.IRCMessage) error {
// Send a built ircmsg.Message.
func (irc *Connection) SendIRCMessage(msg ircmsg.Message) error {
b, err := msg.LineBytesStrict(true, irc.MaxLineLen)
if err != nil {
if irc.Debug {

View File

@ -23,10 +23,10 @@ type CallbackID struct {
}
// Register a callback to a connection and event code. A callback is a function
// which takes only an Event object as parameter. Valid event codes are all
// which takes only an ircmsg.Message object as parameter. Valid event codes are all
// IRC/CTCP commands and error/response codes. This function returns the ID of the
// registered callback for later management.
func (irc *Connection) AddCallback(eventCode string, callback func(Event)) CallbackID {
func (irc *Connection) AddCallback(eventCode string, callback func(ircmsg.Message)) CallbackID {
return irc.addCallback(eventCode, Callback(callback), false, 0)
}
@ -103,7 +103,7 @@ func (irc *Connection) ClearCallback(eventcode string) {
}
// Replace callback i (ID) associated with a given event code with a new callback function.
func (irc *Connection) ReplaceCallback(id CallbackID, callback func(Event)) bool {
func (irc *Connection) ReplaceCallback(id CallbackID, callback func(ircmsg.Message)) bool {
irc.eventsMutex.Lock()
defer irc.eventsMutex.Unlock()
@ -153,7 +153,7 @@ func (irc *Connection) removeBatchCallbackNoMutex(idNum uint64) {
// Convenience function to add a callback that will be called once the
// connection is completed (this is traditionally referred to as "connection
// registration").
func (irc *Connection) AddConnectCallback(callback func(Event)) (id CallbackID) {
func (irc *Connection) AddConnectCallback(callback func(ircmsg.Message)) (id CallbackID) {
// XXX: forcibly use the same ID number for both copies of the callback
id376 := irc.AddCallback(RPL_ENDOFMOTD, callback)
irc.addCallback(ERR_NOMOTD, callback, false, id376.id)
@ -184,7 +184,7 @@ var (
errorUnknownLabel = errors.New("received labeled response from server, but we don't recognize the label")
)
func (irc *Connection) handleBatchCommand(msg ircmsg.IRCMessage) {
func (irc *Connection) handleBatchCommand(msg ircmsg.Message) {
if len(msg.Params) < 1 || len(msg.Params[0]) < 2 {
irc.Log.Printf("Invalid BATCH command from server\n")
return
@ -214,7 +214,7 @@ func (irc *Connection) handleBatchCommand(msg ircmsg.IRCMessage) {
return
}
batchObj := new(Batch)
batchObj.IRCMessage = msg
batchObj.Message = msg
irc.batches[batchID] = batchInProgress{
createdAt: time.Now(),
batch: batchObj,
@ -295,14 +295,14 @@ func (irc *Connection) HandleBatch(batch *Batch) {
// recursively "flatten" the nested batch; process every command individually
func (irc *Connection) handleBatchNaively(batch *Batch) {
if batch.Command != "BATCH" {
irc.HandleEvent(Event{IRCMessage: batch.IRCMessage})
irc.HandleMessage(batch.Message)
}
for _, item := range batch.Items {
irc.handleBatchNaively(item)
}
}
func (irc *Connection) handleBatchedCommand(msg ircmsg.IRCMessage, batchID string) {
func (irc *Connection) handleBatchedCommand(msg ircmsg.Message, batchID string) {
irc.batchMutex.Lock()
defer irc.batchMutex.Unlock()
@ -311,11 +311,11 @@ func (irc *Connection) handleBatchedCommand(msg ircmsg.IRCMessage, batchID strin
irc.Log.Printf("ignoring command with unknown batch ID %s\n", batchID)
return
}
bip.batch.Items = append(bip.batch.Items, &Batch{IRCMessage: msg})
bip.batch.Items = append(bip.batch.Items, &Batch{Message: msg})
}
// Execute all callbacks associated with a given event.
func (irc *Connection) runCallbacks(msg ircmsg.IRCMessage) {
func (irc *Connection) runCallbacks(msg ircmsg.Message) {
if !irc.AllowPanic {
defer func() {
if r := recover(); r != nil {
@ -347,7 +347,7 @@ func (irc *Connection) runCallbacks(msg ircmsg.IRCMessage) {
return
} else {
labelCallback(&Batch{
IRCMessage: msg,
Message: msg,
})
}
return
@ -355,12 +355,12 @@ func (irc *Connection) runCallbacks(msg ircmsg.IRCMessage) {
}
// OK, it's a normal IRC command
irc.HandleEvent(Event{IRCMessage: msg})
irc.HandleMessage(msg)
}
// HandleEvent handles an IRC line using the available handlers. This can be
// HandleMessage handles an IRC line using the available handlers. This can be
// used in a batch or labeled-response callback to process an individual line.
func (irc *Connection) HandleEvent(event Event) {
func (irc *Connection) HandleMessage(event ircmsg.Message) {
if irc.EnableCTCP {
eventRewriteCTCP(&event)
}
@ -386,12 +386,10 @@ func (irc *Connection) setupCallbacks() {
}
// PING: we must respond with the correct PONG
irc.AddCallback("PING", func(e Event) { irc.Send("PONG", e.Message()) })
irc.AddCallback("PING", func(e ircmsg.Message) { irc.Send("PONG", lastParam(&e)) })
// PONG: record time to make sure the server is responding to us
irc.AddCallback("PONG", func(e Event) {
irc.recordPong(e.Message())
})
irc.AddCallback("PONG", func(e ircmsg.Message) { irc.recordPong(lastParam(&e)) })
// 433: ERR_NICKNAMEINUSE "<nick> :Nickname is already in use"
// 437: ERR_UNAVAILRESOURCE "<nick/channel> :Nick/channel is temporarily unavailable"
@ -406,13 +404,13 @@ func (irc *Connection) setupCallbacks() {
irc.AddCallback(RPL_ISUPPORT, irc.handleISupport)
// respond to NICK from the server (in response to our own NICK, or sent unprompted)
irc.AddCallback("NICK", func(e Event) {
if e.Nick() == irc.CurrentNick() && len(e.Params) > 0 {
irc.AddCallback("NICK", func(e ircmsg.Message) {
if ExtractNick(e.Prefix) == irc.CurrentNick() && len(e.Params) > 0 {
irc.setCurrentNick(e.Params[0])
}
})
irc.AddCallback("ERROR", func(e Event) {
irc.AddCallback("ERROR", func(e ircmsg.Message) {
if !irc.isQuitting() {
irc.Log.Printf("ERROR received from server: %s", strings.Join(e.Params, " "))
}
@ -438,7 +436,7 @@ func (irc *Connection) setupCallbacks() {
irc.AddCallback("NOTE", irc.handleStandardReplies)
}
func (irc *Connection) handleRplWelcome(e Event) {
func (irc *Connection) handleRplWelcome(e ircmsg.Message) {
irc.stateMutex.Lock()
defer irc.stateMutex.Unlock()
@ -448,7 +446,7 @@ func (irc *Connection) handleRplWelcome(e Event) {
}
}
func (irc *Connection) handleRegistration(e Event) {
func (irc *Connection) handleRegistration(e ircmsg.Message) {
// wake up Connect() if applicable
defer func() {
select {
@ -471,7 +469,7 @@ func (irc *Connection) handleRegistration(e Event) {
}
func (irc *Connection) handleUnavailableNick(e Event) {
func (irc *Connection) handleUnavailableNick(e ircmsg.Message) {
// only try to change the nick if we're not registered yet,
// otherwise we'll change in response to pingLoop unsuccessfully
// trying to restore the intended nick (swapping one undesired nick
@ -489,7 +487,7 @@ func (irc *Connection) handleUnavailableNick(e Event) {
}
}
func (irc *Connection) handleISupport(e Event) {
func (irc *Connection) handleISupport(e ircmsg.Message) {
irc.stateMutex.Lock()
defer irc.stateMutex.Unlock()
@ -530,7 +528,7 @@ func unescapeISupportValue(in string) (out string) {
return buf.String()
}
func (irc *Connection) handleCAP(e Event) {
func (irc *Connection) handleCAP(e ircmsg.Message) {
if len(e.Params) < 3 {
return
}
@ -666,7 +664,7 @@ func splitCAPToken(token string) (name, value string) {
}
}
func (irc *Connection) handleStandardReplies(e Event) {
func (irc *Connection) handleStandardReplies(e ircmsg.Message) {
// unconditionally print messages for FAIL and WARN;
// re. NOTE, if debug is enabled, we print the raw line anyway
switch e.Command {

View File

@ -4,9 +4,11 @@ import (
"fmt"
"strings"
"time"
"github.com/goshuirc/irc-go/ircmsg"
)
func eventRewriteCTCP(event *Event) {
func eventRewriteCTCP(event *ircmsg.Message) {
// XXX rewrite event.Command for CTCP
if !(event.Command == "PRIVMSG" && len(event.Params) == 2 && strings.HasPrefix(event.Params[1], "\x01")) {
return
@ -44,21 +46,23 @@ func eventRewriteCTCP(event *Event) {
}
func (irc *Connection) setupCTCPCallbacks() {
irc.AddCallback("CTCP_VERSION", func(e Event) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01VERSION %s\x01", e.Nick(), irc.Version))
irc.AddCallback("CTCP_VERSION", func(e ircmsg.Message) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01VERSION %s\x01", ExtractNick(e.Prefix), irc.Version))
})
irc.AddCallback("CTCP_USERINFO", func(e Event) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01USERINFO %s\x01", e.Nick(), irc.User))
irc.AddCallback("CTCP_USERINFO", func(e ircmsg.Message) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01USERINFO %s\x01", ExtractNick(e.Prefix), irc.User))
})
irc.AddCallback("CTCP_CLIENTINFO", func(e Event) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01", e.Nick()))
irc.AddCallback("CTCP_CLIENTINFO", func(e ircmsg.Message) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01", ExtractNick(e.Prefix)))
})
irc.AddCallback("CTCP_TIME", func(e Event) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01TIME %s\x01", e.Nick(), time.Now().UTC().Format(time.RFC1123)))
irc.AddCallback("CTCP_TIME", func(e ircmsg.Message) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01TIME %s\x01", ExtractNick(e.Prefix), time.Now().UTC().Format(time.RFC1123)))
})
irc.AddCallback("CTCP_PING", func(e Event) { irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01%s\x01", e.Nick(), e.Message())) })
irc.AddCallback("CTCP_PING", func(e ircmsg.Message) {
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01%s\x01", ExtractNick(e.Prefix), e.Params[1]))
})
}

View File

@ -6,6 +6,8 @@ import (
"encoding/hex"
"fmt"
"testing"
"github.com/goshuirc/irc-go/ircmsg"
)
const (
@ -21,7 +23,7 @@ func TestLabeledResponse(t *testing.T) {
irccon.RequestCaps = []string{"message-tags", "batch", "labeled-response"}
irccon.RealName = "ecf61da38b58"
results := make(map[string]string)
irccon.AddConnectCallback(func(e Event) {
irccon.AddConnectCallback(func(e ircmsg.Message) {
irccon.SendWithLabel(func(batch *Batch) {
if batch == nil {
return
@ -192,7 +194,7 @@ func TestBatchHandlers(t *testing.T) {
}
return false
})
alice.AddCallback("PRIVMSG", func(e Event) {
alice.AddCallback("PRIVMSG", func(e ircmsg.Message) {
alicePrivmsgCount++
})

View File

@ -7,16 +7,16 @@ import (
)
func TestParse(t *testing.T) {
event := new(Event)
event.Prefix = "nick!~user@host"
source := "nick!~user@host"
nick, user, host := SplitNUH(source)
if event.Nick() != "nick" {
if nick != "nick" {
t.Fatal("Parse failed: nick")
}
if event.User() != "~user" {
if user != "~user" {
t.Fatal("Parse failed: user")
}
if event.Host() != "host" {
if host != "host" {
t.Fatal("Parse failed: host")
}
}

View File

@ -4,6 +4,8 @@ import (
"encoding/base64"
"errors"
"fmt"
"github.com/goshuirc/irc-go/ircmsg"
)
type saslResult struct {
@ -28,35 +30,35 @@ func (irc *Connection) submitSASLResult(r saslResult) {
}
func (irc *Connection) setupSASLCallbacks() {
irc.AddCallback("AUTHENTICATE", func(e Event) {
irc.AddCallback("AUTHENTICATE", func(e ircmsg.Message) {
str := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s\x00%s\x00%s", irc.SASLLogin, irc.SASLLogin, irc.SASLPassword)))
irc.Send("AUTHENTICATE", str)
})
irc.AddCallback(RPL_LOGGEDOUT, func(e Event) {
irc.AddCallback(RPL_LOGGEDOUT, func(e ircmsg.Message) {
irc.SendRaw("CAP END")
irc.SendRaw("QUIT")
irc.submitSASLResult(saslResult{true, errors.New(e.Params[1])})
})
irc.AddCallback(ERR_NICKLOCKED, func(e Event) {
irc.AddCallback(ERR_NICKLOCKED, func(e ircmsg.Message) {
irc.SendRaw("CAP END")
irc.SendRaw("QUIT")
irc.submitSASLResult(saslResult{true, errors.New(e.Params[1])})
})
irc.AddCallback(RPL_SASLSUCCESS, func(e Event) {
irc.AddCallback(RPL_SASLSUCCESS, func(e ircmsg.Message) {
irc.submitSASLResult(saslResult{false, nil})
})
irc.AddCallback(ERR_SASLFAIL, func(e Event) {
irc.AddCallback(ERR_SASLFAIL, func(e ircmsg.Message) {
irc.SendRaw("CAP END")
irc.SendRaw("QUIT")
irc.submitSASLResult(saslResult{true, errors.New(e.Params[1])})
})
// this could potentially happen with auto-login via certfp?
irc.AddCallback(ERR_SASLALREADY, func(e Event) {
irc.AddCallback(ERR_SASLALREADY, func(e ircmsg.Message) {
irc.submitSASLResult(saslResult{false, nil})
})
}

View File

@ -5,6 +5,8 @@ import (
"fmt"
"os"
"testing"
"github.com/goshuirc/irc-go/ircmsg"
)
const (
@ -48,9 +50,9 @@ func runCAPTest(caps []string, useSASL bool, t *testing.T) {
}
irccon.RequestCaps = caps
irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
irccon.AddCallback("001", func(e Event) { irccon.Join("#go-eventirc") })
irccon.AddCallback("001", func(e ircmsg.Message) { irccon.Join("#go-eventirc") })
irccon.AddCallback("366", func(e Event) {
irccon.AddCallback("366", func(e ircmsg.Message) {
irccon.Privmsg("#go-eventirc", "Test Message SASL")
irccon.Quit()
})
@ -96,7 +98,7 @@ func TestSASLFail(t *testing.T) {
irccon.UseTLS = true
setSaslTestCreds(irccon, t)
irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
irccon.AddCallback("001", func(e Event) { irccon.Join("#go-eventirc") })
irccon.AddCallback("001", func(e ircmsg.Message) { irccon.Join("#go-eventirc") })
// intentionally break the password
irccon.SASLPassword = irccon.SASLPassword + "_"
err := irccon.Connect()

View File

@ -17,7 +17,7 @@ import (
type empty struct{}
type Callback func(Event)
type Callback func(ircmsg.Message)
type callbackPair struct {
id uint64
@ -65,7 +65,7 @@ type Connection struct {
// networking and synchronization
stateMutex sync.Mutex // innermost mutex: don't block while holding this
end chan empty // closing this causes the goroutines to exit (think threading.Event)
end chan empty // closing this causes the goroutines to exit
pwrite chan []byte // receives IRC lines to be sent to the socket
wg sync.WaitGroup // after closing end, wait on this for all the goroutines to stop
socket net.Conn
@ -123,74 +123,40 @@ type pendingLabel struct {
callback LabelCallback
}
// Event represents an individual IRC line.
type Event struct {
ircmsg.IRCMessage
}
// Batch represents an IRCv3 batch, or a line within one. There are
// two cases:
// 1. (Batch).Command == "BATCH". This indicates the start of an IRCv3
// batch; the embedded IRCMessage is the initial BATCH command, which
// batch; the embedded Message is the initial BATCH command, which
// may contain tags that pertain to the batch as a whole. (Batch).Items
// contains zero or more *Batch elements, pointing to the contents of
// the batch in order.
// 2. (Batch).Command != "BATCH". This is an ordinary IRC line; its
// tags, command, and parameters are available as members of the embedded
// IRCMessage.
// Message.
// In the context of labeled-response, there is a third case: a `nil`
// value of *Batch indicates that the server failed to respond in time.
type Batch struct {
ircmsg.IRCMessage
ircmsg.Message
Items []*Batch
}
// Retrieve the last message from Event arguments.
// This function leaves the arguments untouched and
// returns an empty string if there are none.
func (e *Event) Message() string {
if len(e.Params) == 0 {
return ""
}
return e.Params[len(e.Params)-1]
}
/*
// https://stackoverflow.com/a/10567935/6754440
// Regex of IRC formatting.
var ircFormat = regexp.MustCompile(`[\x02\x1F\x0F\x16\x1D\x1E]|\x03(\d\d?(,\d\d?)?)?`)
// Retrieve the last message from Event arguments, but without IRC formatting (color.
// This function leaves the arguments untouched and
// returns an empty string if there are none.
func (e *Event) MessageWithoutFormat() string {
if len(e.Arguments) == 0 {
return ""
}
return ircFormat.ReplaceAllString(e.Arguments[len(e.Arguments)-1], "")
}
*/
func (e *Event) Nick() string {
nick, _, _ := e.splitNUH()
func ExtractNick(source string) string {
nick, _, _ := SplitNUH(source)
return nick
}
func (e *Event) User() string {
_, user, _ := e.splitNUH()
return user
}
func (e *Event) Host() string {
_, _, host := e.splitNUH()
return host
}
func (event *Event) splitNUH() (nick, user, host string) {
if i, j := strings.Index(event.Prefix, "!"), strings.Index(event.Prefix, "@"); i > -1 && j > -1 && i < j {
nick = event.Prefix[0:i]
user = event.Prefix[i+1 : j]
host = event.Prefix[j+1:]
func SplitNUH(source string) (nick, user, host string) {
if i, j := strings.Index(source, "!"), strings.Index(source, "@"); i > -1 && j > -1 && i < j {
nick = source[0:i]
user = source[i+1 : j]
host = source[j+1:]
}
return
}
func lastParam(msg *ircmsg.Message) (result string) {
if 0 < len(msg.Params) {
return msg.Params[len(msg.Params)-1]
}
return
}

View File

@ -27,7 +27,7 @@ func connForTesting(nick, user string, tls bool) *Connection {
return irc
}
func mockEvent(command string) ircmsg.IRCMessage {
func mockEvent(command string) ircmsg.Message {
return ircmsg.MakeMessage(nil, ":server.name", command)
}
@ -37,9 +37,9 @@ func TestRemoveCallback(t *testing.T) {
done := make(chan int, 10)
irccon.AddCallback("TEST", func(e Event) { done <- 1 })
id := irccon.AddCallback("TEST", func(e Event) { done <- 2 })
irccon.AddCallback("TEST", func(e Event) { done <- 3 })
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 1 })
id := irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 2 })
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 3 })
// Should remove callback at index 1
irccon.RemoveCallback(id)
@ -62,11 +62,11 @@ func TestClearCallback(t *testing.T) {
done := make(chan int, 10)
irccon.AddCallback("TEST", func(e Event) { done <- 0 })
irccon.AddCallback("TEST", func(e Event) { done <- 1 })
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 0 })
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 1 })
irccon.ClearCallback("TEST")
irccon.AddCallback("TEST", func(e Event) { done <- 2 })
irccon.AddCallback("TEST", func(e Event) { done <- 3 })
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 2 })
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 3 })
irccon.runCallbacks(mockEvent("TEST"))
@ -106,10 +106,10 @@ func TestConnection(t *testing.T) {
teststr := randStr(20)
testmsgok := make(chan bool, 1)
irccon1.AddCallback("001", func(e Event) { irccon1.Join(channel) })
irccon2.AddCallback("001", func(e Event) { irccon2.Join(channel) })
irccon1.AddCallback("366", func(e Event) {
go func(e Event) {
irccon1.AddCallback("001", func(e ircmsg.Message) { irccon1.Join(channel) })
irccon2.AddCallback("001", func(e ircmsg.Message) { irccon2.Join(channel) })
irccon1.AddCallback("366", func(e ircmsg.Message) {
go func(e ircmsg.Message) {
tick := time.NewTicker(1 * time.Second)
i := 10
for {
@ -131,14 +131,14 @@ func TestConnection(t *testing.T) {
}(e)
})
irccon2.AddCallback("366", func(e Event) {
irccon2.AddCallback("366", func(e ircmsg.Message) {
ircnick2 = randStr(8)
irccon2.SetNick(ircnick2)
})
irccon2.AddCallback("PRIVMSG", func(e Event) {
if e.Message() == teststr {
if e.Nick() == ircnick1 {
irccon2.AddCallback("PRIVMSG", func(e ircmsg.Message) {
if e.Params[1] == teststr {
if ExtractNick(e.Prefix) == ircnick1 {
testmsgok <- true
irccon2.Quit()
} else {
@ -150,8 +150,8 @@ func TestConnection(t *testing.T) {
}
})
irccon2.AddCallback("NICK", func(e Event) {
if !(e.Nick() == ircnick2orig && e.Message() == ircnick2) {
irccon2.AddCallback("NICK", func(e ircmsg.Message) {
if !(ExtractNick(e.Prefix) == ircnick2orig && e.Params[0] == ircnick2) {
t.Errorf("Nick change did not work!")
}
})
@ -181,9 +181,9 @@ func runReconnectTest(useSASL bool, t *testing.T) {
debugTest(irccon)
connects := 0
irccon.AddCallback("001", func(e Event) { irccon.Join(channel) })
irccon.AddCallback("001", func(e ircmsg.Message) { irccon.Join(channel) })
irccon.AddCallback("366", func(e Event) {
irccon.AddCallback("366", func(e ircmsg.Message) {
connects += 1
if connects > 2 {
irccon.Privmsgf(channel, "Connection nr %d (test done)", connects)
@ -226,9 +226,9 @@ func TestConnectionSSL(t *testing.T) {
debugTest(irccon)
irccon.UseTLS = true
irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
irccon.AddCallback("001", func(e Event) { irccon.Join(channel) })
irccon.AddCallback("001", func(e ircmsg.Message) { irccon.Join(channel) })
irccon.AddCallback("366", func(e Event) {
irccon.AddCallback("366", func(e ircmsg.Message) {
irccon.Privmsg(channel, "Test Message from SSL")
irccon.Quit()
})
@ -284,8 +284,8 @@ func TestConnectionNickInUse(t *testing.T) {
n2 := make(chan string, 1)
// check the actual nick after 001 is processed
irccon1.AddCallback("002", func(e Event) { n1 <- irccon1.CurrentNick() })
irccon2.AddCallback("002", func(e Event) { n2 <- irccon2.CurrentNick() })
irccon1.AddCallback("002", func(e ircmsg.Message) { n1 <- irccon1.CurrentNick() })
irccon2.AddCallback("002", func(e ircmsg.Message) { n2 <- irccon2.CurrentNick() })
err := irccon1.Connect()
if err != nil {
@ -318,7 +318,7 @@ func TestConnectionCallbacks(t *testing.T) {
irccon1 := connForTesting(ircnick, "IRCTest1", false)
debugTest(irccon1)
resultChan := make(chan map[string]string, 1)
irccon1.AddConnectCallback(func(e Event) {
irccon1.AddConnectCallback(func(e ircmsg.Message) {
resultChan <- irccon1.ISupport()
})
err := irccon1.Connect()

View File

@ -61,10 +61,10 @@ var (
ErrorBadParam = errors.New("Cannot have an empty param, a param with spaces, or a param that starts with ':' before the last parameter")
)
// IRCMessage represents an IRC message, as defined by the RFCs and as
// Message represents an IRC message, as defined by the RFCs and as
// extended by the IRCv3 Message Tags specification with the introduction
// of message tags.
type IRCMessage struct {
type Message struct {
Prefix string
Command string
Params []string
@ -77,12 +77,12 @@ type IRCMessage struct {
// will be encoded as a "trailing parameter" (preceded by a colon). This is
// almost never necessary and should not be used except when having to interact
// with broken implementations that don't correctly interpret IRC messages.
func (msg *IRCMessage) ForceTrailing() {
func (msg *Message) ForceTrailing() {
msg.forceTrailing = true
}
// GetTag returns whether a tag is present, and if so, what its value is.
func (msg *IRCMessage) GetTag(tagName string) (present bool, value string) {
func (msg *Message) GetTag(tagName string) (present bool, value string) {
if len(tagName) == 0 {
return
} else if tagName[0] == '+' {
@ -95,13 +95,13 @@ func (msg *IRCMessage) GetTag(tagName string) (present bool, value string) {
}
// HasTag returns whether a tag is present.
func (msg *IRCMessage) HasTag(tagName string) (present bool) {
func (msg *Message) HasTag(tagName string) (present bool) {
present, _ = msg.GetTag(tagName)
return
}
// SetTag sets a tag.
func (msg *IRCMessage) SetTag(tagName, tagValue string) {
func (msg *Message) SetTag(tagName, tagValue string) {
if len(tagName) == 0 {
return
} else if tagName[0] == '+' {
@ -118,7 +118,7 @@ func (msg *IRCMessage) SetTag(tagName, tagValue string) {
}
// DeleteTag deletes a tag.
func (msg *IRCMessage) DeleteTag(tagName string) {
func (msg *Message) DeleteTag(tagName string) {
if len(tagName) == 0 {
return
} else if tagName[0] == '+' {
@ -129,14 +129,14 @@ func (msg *IRCMessage) DeleteTag(tagName string) {
}
// UpdateTags is a convenience to set multiple tags at once.
func (msg *IRCMessage) UpdateTags(tags map[string]string) {
func (msg *Message) UpdateTags(tags map[string]string) {
for name, value := range tags {
msg.SetTag(name, value)
}
}
// AllTags returns all tags as a single map.
func (msg *IRCMessage) AllTags() (result map[string]string) {
func (msg *Message) AllTags() (result map[string]string) {
result = make(map[string]string, len(msg.tags)+len(msg.clientOnlyTags))
for name, value := range msg.tags {
result[name] = value
@ -148,23 +148,23 @@ func (msg *IRCMessage) AllTags() (result map[string]string) {
}
// ClientOnlyTags returns the client-only tags (the tags with the + prefix).
// The returned map may be internal storage of the IRCMessage object and
// The returned map may be internal storage of the Message object and
// should not be modified.
func (msg *IRCMessage) ClientOnlyTags() map[string]string {
func (msg *Message) ClientOnlyTags() map[string]string {
return msg.clientOnlyTags
}
// ParseLine creates and returns a message from the given IRC line.
func ParseLine(line string) (ircmsg IRCMessage, err error) {
func ParseLine(line string) (ircmsg Message, err error) {
return parseLine(line, 0, 0)
}
// ParseLineStrict creates and returns an IRCMessage from the given IRC line,
// ParseLineStrict creates and returns an Message from the given IRC line,
// taking the maximum length into account and truncating the message as appropriate.
// If fromClient is true, it enforces the client limit on tag data length (4094 bytes),
// allowing the server to return ERR_INPUTTOOLONG as appropriate. If truncateLen is
// nonzero, it is the length at which the non-tag portion of the message is truncated.
func ParseLineStrict(line string, fromClient bool, truncateLen int) (ircmsg IRCMessage, err error) {
func ParseLineStrict(line string, fromClient bool, truncateLen int) (ircmsg Message, err error) {
maxTagDataLength := MaxlenTagData
if fromClient {
maxTagDataLength = MaxlenClientTagData
@ -180,7 +180,7 @@ func trimInitialSpaces(str string) string {
return str[i:]
}
func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg IRCMessage, err error) {
func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg Message, err error) {
// remove either \n or \r\n from the end of the line:
line = strings.TrimSuffix(line, "\n")
line = strings.TrimSuffix(line, "\r")
@ -279,7 +279,7 @@ func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg IRCMe
}
// helper to parse tags
func (ircmsg *IRCMessage) parseTags(tags string) (err error) {
func (ircmsg *Message) parseTags(tags string) (err error) {
for 0 < len(tags) {
tagEnd := strings.IndexByte(tags, ';')
endPos := tagEnd
@ -311,8 +311,8 @@ func (ircmsg *IRCMessage) parseTags(tags string) (err error) {
return nil
}
// MakeMessage provides a simple way to create a new IRCMessage.
func MakeMessage(tags map[string]string, prefix string, command string, params ...string) (ircmsg IRCMessage) {
// MakeMessage provides a simple way to create a new Message.
func MakeMessage(tags map[string]string, prefix string, command string, params ...string) (ircmsg Message) {
ircmsg.Prefix = prefix
ircmsg.Command = command
ircmsg.Params = params
@ -320,8 +320,8 @@ func MakeMessage(tags map[string]string, prefix string, command string, params .
return ircmsg
}
// Line returns a sendable line created from an IRCMessage.
func (ircmsg *IRCMessage) Line() (result string, err error) {
// Line returns a sendable line created from an Message.
func (ircmsg *Message) Line() (result string, err error) {
bytes, err := ircmsg.line(0, 0, 0, 0)
if err == nil {
result = string(bytes)
@ -329,17 +329,17 @@ func (ircmsg *IRCMessage) Line() (result string, err error) {
return
}
// LineBytes returns a sendable line created from an IRCMessage.
func (ircmsg *IRCMessage) LineBytes() (result []byte, err error) {
// LineBytes returns a sendable line created from an Message.
func (ircmsg *Message) LineBytes() (result []byte, err error) {
result, err = ircmsg.line(0, 0, 0, 0)
return
}
// LineBytesStrict returns a sendable line, as a []byte, created from an IRCMessage.
// LineBytesStrict returns a sendable line, as a []byte, created from an Message.
// fromClient controls whether the server-side or client-side tag length limit
// is enforced. If truncateLen is nonzero, it is the length at which the
// non-tag portion of the message is truncated.
func (ircmsg *IRCMessage) LineBytesStrict(fromClient bool, truncateLen int) ([]byte, error) {
func (ircmsg *Message) LineBytesStrict(fromClient bool, truncateLen int) ([]byte, error) {
var tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit int
if fromClient {
// enforce client max tags:
@ -359,8 +359,8 @@ func paramRequiresTrailing(param string) bool {
return len(param) == 0 || strings.IndexByte(param, ' ') != -1 || param[0] == ':'
}
// line returns a sendable line created from an IRCMessage.
func (ircmsg *IRCMessage) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) (result []byte, err error) {
// line returns a sendable line created from an Message.
func (ircmsg *Message) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) (result []byte, err error) {
if len(ircmsg.Command) == 0 {
return nil, ErrorCommandMissing
}

View File

@ -11,12 +11,12 @@ import (
type testcode struct {
raw string
message IRCMessage
message Message
}
type testcodewithlen struct {
raw string
length int
message IRCMessage
message Message
truncateExpected bool
}
@ -256,7 +256,7 @@ func TestEncodeErrors(t *testing.T) {
}
}
var testMessages = []IRCMessage{
var testMessages = []Message{
{
tags: map[string]string{"time": "2019-02-27T04:38:57.489Z", "account": "dan-"},
clientOnlyTags: map[string]string{"+status": "typing"},
@ -329,7 +329,7 @@ func TestEncodeDecode(t *testing.T) {
}
func TestForceTrailing(t *testing.T) {
message := IRCMessage{
message := Message{
Prefix: "shivaram",
Command: "PRIVMSG",
Params: []string{"#darwin", "nice"},
@ -352,7 +352,7 @@ func TestForceTrailing(t *testing.T) {
}
func TestErrorLineTooLongGeneration(t *testing.T) {
message := IRCMessage{
message := Message{
tags: map[string]string{"draft/msgid": "SAXV5OYJUr18CNJzdWa1qQ"},
Prefix: "shivaram",
Command: "PRIVMSG",

View File

@ -30,7 +30,7 @@ func init() {
// EscapeTagValue takes a value, and returns an escaped message tag value.
//
// This function is automatically used when lines are created from an
// IRCMessage, so you don't need to call it yourself before creating a line.
// Message, so you don't need to call it yourself before creating a line.
func EscapeTagValue(inString string) string {
return valtoescape.Replace(inString)
}

View File

@ -10,7 +10,7 @@ import (
)
/*
IRCReader is an optimized line reader for IRC lines containing tags;
Reader is an optimized line reader for IRC lines containing tags;
most IRC lines will not approach the maximum line length (8191 bytes
of tag data, plus 512 bytes of message data), so we want a buffered
reader that can start with a smaller buffer and expand if necessary,
@ -21,7 +21,7 @@ var (
ErrReadQ = errors.New("readQ exceeded (read too many bytes without terminating newline)")
)
type IRCReader struct {
type Reader struct {
conn io.Reader
initialSize int
@ -34,17 +34,17 @@ type IRCReader struct {
eof bool
}
// Returns a new *IRCReader with sane buffer size limits.
func NewIRCReader(conn io.Reader) *IRCReader {
var reader IRCReader
// Returns a new *Reader with sane buffer size limits.
func NewIRCReader(conn io.Reader) *Reader {
var reader Reader
reader.Initialize(conn, 512, 8192+1024)
return &reader
}
// "Placement new" for an IRCReader; initializes it with custom buffer size
// "Placement new" for a Reader; initializes it with custom buffer size
// limits.
func (cc *IRCReader) Initialize(conn io.Reader, initialSize, maxSize int) {
*cc = IRCReader{}
func (cc *Reader) Initialize(conn io.Reader, initialSize, maxSize int) {
*cc = Reader{}
cc.conn = conn
cc.initialSize = initialSize
cc.maxSize = maxSize
@ -54,7 +54,7 @@ func (cc *IRCReader) Initialize(conn io.Reader, initialSize, maxSize int) {
// or \r\n as the line terminator (but not \r in isolation). Passes through
// errors from the underlying connection. Returns ErrReadQ if the buffer limit
// was exceeded without a terminating \n.
func (cc *IRCReader) ReadLine() ([]byte, error) {
func (cc *Reader) ReadLine() ([]byte, error) {
for {
// try to find a terminated line in the buffered data already read
nlidx := bytes.IndexByte(cc.buf[cc.searchFrom:cc.end], '\n')

View File

@ -158,7 +158,7 @@ func TestRegression(t *testing.T) {
// this terminates the previous read, within the acceptable limit:
c.reads = append(c.reads, makeLine(500, true))
var cc IRCReader
var cc Reader
cc.Initialize(&c, 512, 4096+512)
line, err := cc.ReadLine()