Merge pull request #51 from slingamn/noevent.2
rename to Message and Reader; remove Event
This commit is contained in:
commit
ea7a188a73
@ -23,12 +23,12 @@ irc := ircevent.Connection{
|
|||||||
RequestCaps: []string{"server-time", "message-tags"},
|
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) {
|
irc.AddCallback("PRIVMSG", func(event ircmsg.Message) {
|
||||||
//event.Message() contains the message
|
// event.Prefix is the source;
|
||||||
//event.Nick() Contains the sender
|
// event.Params[0] is the target (the channel or nickname the message was sent to)
|
||||||
//event.Params[0] Contains the channel
|
// and event.Params[1] is the message itself
|
||||||
});
|
});
|
||||||
|
|
||||||
err := irc.Connect()
|
err := irc.Connect()
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/goshuirc/irc-go/ircevent"
|
"github.com/goshuirc/irc-go/ircevent"
|
||||||
|
"github.com/goshuirc/irc-go/ircmsg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getenv(key, defaultValue string) (value string) {
|
func getenv(key, defaultValue string) (value string) {
|
||||||
@ -36,15 +37,15 @@ func main() {
|
|||||||
SASLPassword: saslPassword,
|
SASLPassword: saslPassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
irc.AddConnectCallback(func(e ircevent.Event) {
|
irc.AddConnectCallback(func(e ircmsg.Message) {
|
||||||
// attempt to set the BOT mode on ourself:
|
// attempt to set the BOT mode on ourself:
|
||||||
if botMode := irc.ISupport()["BOT"]; botMode != "" {
|
if botMode := irc.ISupport()["BOT"]; botMode != "" {
|
||||||
irc.Send("MODE", irc.CurrentNick(), "+"+botMode)
|
irc.Send("MODE", irc.CurrentNick(), "+"+botMode)
|
||||||
}
|
}
|
||||||
irc.Join(channel)
|
irc.Join(channel)
|
||||||
})
|
})
|
||||||
irc.AddCallback("JOIN", func(e ircevent.Event) {}) // TODO try to rejoin if we *don't* get this
|
irc.AddCallback("JOIN", func(e ircmsg.Message) {}) // TODO try to rejoin if we *don't* get this
|
||||||
irc.AddCallback("PRIVMSG", func(e ircevent.Event) {
|
irc.AddCallback("PRIVMSG", func(e ircmsg.Message) {
|
||||||
if len(e.Params) < 2 {
|
if len(e.Params) < 2 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -65,7 +66,7 @@ func main() {
|
|||||||
// example client-to-client extension via message-tags:
|
// example client-to-client extension via message-tags:
|
||||||
// have the bot maintain a running sum of integers
|
// 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
|
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")
|
_, tv := e.GetTag("+summand")
|
||||||
if v, err := strconv.ParseInt(tv, 10, 64); err == nil {
|
if v, err := strconv.ParseInt(tv, 10, 64); err == nil {
|
||||||
sum += v
|
sum += v
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
_ "net/http/pprof"
|
_ "net/http/pprof"
|
||||||
|
|
||||||
"github.com/goshuirc/irc-go/ircevent"
|
"github.com/goshuirc/irc-go/ircevent"
|
||||||
|
"github.com/goshuirc/irc-go/ircmsg"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -48,11 +49,11 @@ func main() {
|
|||||||
RequestCaps: []string{"server-time", "echo-message"},
|
RequestCaps: []string{"server-time", "echo-message"},
|
||||||
}
|
}
|
||||||
|
|
||||||
irc.AddCallback("001", func(e ircevent.Event) { irc.Join(channel) })
|
irc.AddCallback("001", func(e ircmsg.Message) { irc.Join(channel) })
|
||||||
irc.AddCallback("JOIN", func(e ircevent.Event) { irc.Privmsg(channel, "hi there friend!") })
|
irc.AddCallback("JOIN", func(e ircmsg.Message) { irc.Privmsg(channel, "hi there friend!") })
|
||||||
// echo whatever we get back
|
// echo whatever we get back
|
||||||
count := 0
|
count := 0
|
||||||
irc.AddCallback("PRIVMSG", func(e ircevent.Event) {
|
irc.AddCallback("PRIVMSG", func(e ircmsg.Message) {
|
||||||
if limit != 0 && count >= limit {
|
if limit != 0 && count >= limit {
|
||||||
irc.Quit()
|
irc.Quit()
|
||||||
} else {
|
} else {
|
||||||
|
@ -142,7 +142,7 @@ func (irc *Connection) readLoop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func readMsgLoop(socket net.Conn, maxLineLen int, msgChan chan string, errChan chan error, end chan empty) {
|
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)
|
reader.Initialize(socket, 1024, maxLineLen+maxlenTags)
|
||||||
for {
|
for {
|
||||||
msgBytes, err := reader.ReadLine()
|
msgBytes, err := reader.ReadLine()
|
||||||
@ -348,8 +348,8 @@ func (irc *Connection) sendInternal(b []byte) (err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a built ircmsg.IRCMessage.
|
// Send a built ircmsg.Message.
|
||||||
func (irc *Connection) SendIRCMessage(msg ircmsg.IRCMessage) error {
|
func (irc *Connection) SendIRCMessage(msg ircmsg.Message) error {
|
||||||
b, err := msg.LineBytesStrict(true, irc.MaxLineLen)
|
b, err := msg.LineBytesStrict(true, irc.MaxLineLen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if irc.Debug {
|
if irc.Debug {
|
||||||
|
@ -18,21 +18,21 @@ const (
|
|||||||
|
|
||||||
// Tuple type for uniquely identifying callbacks
|
// Tuple type for uniquely identifying callbacks
|
||||||
type CallbackID struct {
|
type CallbackID struct {
|
||||||
eventCode string
|
command string
|
||||||
id uint64
|
id uint64
|
||||||
}
|
}
|
||||||
|
|
||||||
// Register a callback to a connection and event code. A callback is a function
|
// Register a callback to handle an IRC command (or numeric). A callback is a
|
||||||
// which takes only an Event object as parameter. Valid event codes are all
|
// function which takes only an ircmsg.Message object as parameter. Valid commands
|
||||||
// IRC/CTCP commands and error/response codes. This function returns the ID of the
|
// are all IRC commands, including numerics. This function returns the ID of the
|
||||||
// registered callback for later management.
|
// registered callback for later management.
|
||||||
func (irc *Connection) AddCallback(eventCode string, callback func(Event)) CallbackID {
|
func (irc *Connection) AddCallback(command string, callback func(ircmsg.Message)) CallbackID {
|
||||||
return irc.addCallback(eventCode, Callback(callback), false, 0)
|
return irc.addCallback(command, Callback(callback), false, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (irc *Connection) addCallback(eventCode string, callback Callback, prepend bool, idNum uint64) CallbackID {
|
func (irc *Connection) addCallback(command string, callback Callback, prepend bool, idNum uint64) CallbackID {
|
||||||
eventCode = strings.ToUpper(eventCode)
|
command = strings.ToUpper(command)
|
||||||
if eventCode == "" || strings.HasPrefix(eventCode, "*") || eventCode == "BATCH" {
|
if command == "" || strings.HasPrefix(command, "*") || command == "BATCH" {
|
||||||
return CallbackID{}
|
return CallbackID{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,9 +47,9 @@ func (irc *Connection) addCallback(eventCode string, callback Callback, prepend
|
|||||||
idNum = irc.callbackCounter
|
idNum = irc.callbackCounter
|
||||||
irc.callbackCounter++
|
irc.callbackCounter++
|
||||||
}
|
}
|
||||||
id := CallbackID{eventCode: eventCode, id: idNum}
|
id := CallbackID{command: command, id: idNum}
|
||||||
newPair := callbackPair{id: id.id, callback: callback}
|
newPair := callbackPair{id: id.id, callback: callback}
|
||||||
current := irc.events[eventCode]
|
current := irc.events[command]
|
||||||
newList := make([]callbackPair, len(current)+1)
|
newList := make([]callbackPair, len(current)+1)
|
||||||
start := 0
|
start := 0
|
||||||
if prepend {
|
if prepend {
|
||||||
@ -60,7 +60,7 @@ func (irc *Connection) addCallback(eventCode string, callback Callback, prepend
|
|||||||
if !prepend {
|
if !prepend {
|
||||||
newList[len(newList)-1] = newPair
|
newList[len(newList)-1] = newPair
|
||||||
}
|
}
|
||||||
irc.events[eventCode] = newList
|
irc.events[command] = newList
|
||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -68,14 +68,14 @@ func (irc *Connection) addCallback(eventCode string, callback Callback, prepend
|
|||||||
func (irc *Connection) RemoveCallback(id CallbackID) {
|
func (irc *Connection) RemoveCallback(id CallbackID) {
|
||||||
irc.eventsMutex.Lock()
|
irc.eventsMutex.Lock()
|
||||||
defer irc.eventsMutex.Unlock()
|
defer irc.eventsMutex.Unlock()
|
||||||
switch id.eventCode {
|
switch id.command {
|
||||||
case registrationEvent:
|
case registrationEvent:
|
||||||
irc.removeCallbackNoMutex(RPL_ENDOFMOTD, id.id)
|
irc.removeCallbackNoMutex(RPL_ENDOFMOTD, id.id)
|
||||||
irc.removeCallbackNoMutex(ERR_NOMOTD, id.id)
|
irc.removeCallbackNoMutex(ERR_NOMOTD, id.id)
|
||||||
case "BATCH":
|
case "BATCH":
|
||||||
irc.removeBatchCallbackNoMutex(id.id)
|
irc.removeBatchCallbackNoMutex(id.id)
|
||||||
default:
|
default:
|
||||||
irc.removeCallbackNoMutex(id.eventCode, id.id)
|
irc.removeCallbackNoMutex(id.command, id.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,20 +94,20 @@ func (irc *Connection) removeCallbackNoMutex(code string, id uint64) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Remove all callbacks from a given event code.
|
// Remove all callbacks from a given event code.
|
||||||
func (irc *Connection) ClearCallback(eventcode string) {
|
func (irc *Connection) ClearCallback(command string) {
|
||||||
eventcode = strings.ToUpper(eventcode)
|
command = strings.ToUpper(command)
|
||||||
|
|
||||||
irc.eventsMutex.Lock()
|
irc.eventsMutex.Lock()
|
||||||
defer irc.eventsMutex.Unlock()
|
defer irc.eventsMutex.Unlock()
|
||||||
delete(irc.events, eventcode)
|
delete(irc.events, command)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Replace callback i (ID) associated with a given event code with a new callback function.
|
// 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()
|
irc.eventsMutex.Lock()
|
||||||
defer irc.eventsMutex.Unlock()
|
defer irc.eventsMutex.Unlock()
|
||||||
|
|
||||||
list := irc.events[id.eventCode]
|
list := irc.events[id.command]
|
||||||
for i, p := range list {
|
for i, p := range list {
|
||||||
if p.id == id.id {
|
if p.id == id.id {
|
||||||
list[i] = callbackPair{id: id.id, callback: callback}
|
list[i] = callbackPair{id: id.id, callback: callback}
|
||||||
@ -133,7 +133,7 @@ func (irc *Connection) AddBatchCallback(callback func(*Batch) bool) CallbackID {
|
|||||||
copy(nbc, irc.batchCallbacks)
|
copy(nbc, irc.batchCallbacks)
|
||||||
nbc[len(nbc)-1] = batchCallbackPair{id: idNum, callback: callback}
|
nbc[len(nbc)-1] = batchCallbackPair{id: idNum, callback: callback}
|
||||||
irc.batchCallbacks = nbc
|
irc.batchCallbacks = nbc
|
||||||
return CallbackID{eventCode: "BATCH", id: idNum}
|
return CallbackID{command: "BATCH", id: idNum}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (irc *Connection) removeBatchCallbackNoMutex(idNum uint64) {
|
func (irc *Connection) removeBatchCallbackNoMutex(idNum uint64) {
|
||||||
@ -153,11 +153,11 @@ func (irc *Connection) removeBatchCallbackNoMutex(idNum uint64) {
|
|||||||
// Convenience function to add a callback that will be called once the
|
// Convenience function to add a callback that will be called once the
|
||||||
// connection is completed (this is traditionally referred to as "connection
|
// connection is completed (this is traditionally referred to as "connection
|
||||||
// registration").
|
// 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
|
// XXX: forcibly use the same ID number for both copies of the callback
|
||||||
id376 := irc.AddCallback(RPL_ENDOFMOTD, callback)
|
id376 := irc.AddCallback(RPL_ENDOFMOTD, callback)
|
||||||
irc.addCallback(ERR_NOMOTD, callback, false, id376.id)
|
irc.addCallback(ERR_NOMOTD, callback, false, id376.id)
|
||||||
return CallbackID{eventCode: registrationEvent, id: id376.id}
|
return CallbackID{command: registrationEvent, id: id376.id}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (irc *Connection) getCallbacks(code string) (result []callbackPair) {
|
func (irc *Connection) getCallbacks(code string) (result []callbackPair) {
|
||||||
@ -184,7 +184,7 @@ var (
|
|||||||
errorUnknownLabel = errors.New("received labeled response from server, but we don't recognize the label")
|
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 {
|
if len(msg.Params) < 1 || len(msg.Params[0]) < 2 {
|
||||||
irc.Log.Printf("Invalid BATCH command from server\n")
|
irc.Log.Printf("Invalid BATCH command from server\n")
|
||||||
return
|
return
|
||||||
@ -214,7 +214,7 @@ func (irc *Connection) handleBatchCommand(msg ircmsg.IRCMessage) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
batchObj := new(Batch)
|
batchObj := new(Batch)
|
||||||
batchObj.IRCMessage = msg
|
batchObj.Message = msg
|
||||||
irc.batches[batchID] = batchInProgress{
|
irc.batches[batchID] = batchInProgress{
|
||||||
createdAt: time.Now(),
|
createdAt: time.Now(),
|
||||||
batch: batchObj,
|
batch: batchObj,
|
||||||
@ -295,14 +295,14 @@ func (irc *Connection) HandleBatch(batch *Batch) {
|
|||||||
// recursively "flatten" the nested batch; process every command individually
|
// recursively "flatten" the nested batch; process every command individually
|
||||||
func (irc *Connection) handleBatchNaively(batch *Batch) {
|
func (irc *Connection) handleBatchNaively(batch *Batch) {
|
||||||
if batch.Command != "BATCH" {
|
if batch.Command != "BATCH" {
|
||||||
irc.HandleEvent(Event{IRCMessage: batch.IRCMessage})
|
irc.HandleMessage(batch.Message)
|
||||||
}
|
}
|
||||||
for _, item := range batch.Items {
|
for _, item := range batch.Items {
|
||||||
irc.handleBatchNaively(item)
|
irc.handleBatchNaively(item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (irc *Connection) handleBatchedCommand(msg ircmsg.IRCMessage, batchID string) {
|
func (irc *Connection) handleBatchedCommand(msg ircmsg.Message, batchID string) {
|
||||||
irc.batchMutex.Lock()
|
irc.batchMutex.Lock()
|
||||||
defer irc.batchMutex.Unlock()
|
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)
|
irc.Log.Printf("ignoring command with unknown batch ID %s\n", batchID)
|
||||||
return
|
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.
|
// 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 {
|
if !irc.AllowPanic {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r != nil {
|
if r := recover(); r != nil {
|
||||||
@ -347,7 +347,7 @@ func (irc *Connection) runCallbacks(msg ircmsg.IRCMessage) {
|
|||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
labelCallback(&Batch{
|
labelCallback(&Batch{
|
||||||
IRCMessage: msg,
|
Message: msg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@ -355,12 +355,12 @@ func (irc *Connection) runCallbacks(msg ircmsg.IRCMessage) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// OK, it's a normal IRC command
|
// 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.
|
// 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 {
|
if irc.EnableCTCP {
|
||||||
eventRewriteCTCP(&event)
|
eventRewriteCTCP(&event)
|
||||||
}
|
}
|
||||||
@ -386,12 +386,10 @@ func (irc *Connection) setupCallbacks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PING: we must respond with the correct PONG
|
// 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
|
// PONG: record time to make sure the server is responding to us
|
||||||
irc.AddCallback("PONG", func(e Event) {
|
irc.AddCallback("PONG", func(e ircmsg.Message) { irc.recordPong(lastParam(&e)) })
|
||||||
irc.recordPong(e.Message())
|
|
||||||
})
|
|
||||||
|
|
||||||
// 433: ERR_NICKNAMEINUSE "<nick> :Nickname is already in use"
|
// 433: ERR_NICKNAMEINUSE "<nick> :Nickname is already in use"
|
||||||
// 437: ERR_UNAVAILRESOURCE "<nick/channel> :Nick/channel is temporarily unavailable"
|
// 437: ERR_UNAVAILRESOURCE "<nick/channel> :Nick/channel is temporarily unavailable"
|
||||||
@ -406,13 +404,13 @@ func (irc *Connection) setupCallbacks() {
|
|||||||
irc.AddCallback(RPL_ISUPPORT, irc.handleISupport)
|
irc.AddCallback(RPL_ISUPPORT, irc.handleISupport)
|
||||||
|
|
||||||
// respond to NICK from the server (in response to our own NICK, or sent unprompted)
|
// respond to NICK from the server (in response to our own NICK, or sent unprompted)
|
||||||
irc.AddCallback("NICK", func(e Event) {
|
irc.AddCallback("NICK", func(e ircmsg.Message) {
|
||||||
if e.Nick() == irc.CurrentNick() && len(e.Params) > 0 {
|
if ExtractNick(e.Prefix) == irc.CurrentNick() && len(e.Params) > 0 {
|
||||||
irc.setCurrentNick(e.Params[0])
|
irc.setCurrentNick(e.Params[0])
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
irc.AddCallback("ERROR", func(e Event) {
|
irc.AddCallback("ERROR", func(e ircmsg.Message) {
|
||||||
if !irc.isQuitting() {
|
if !irc.isQuitting() {
|
||||||
irc.Log.Printf("ERROR received from server: %s", strings.Join(e.Params, " "))
|
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)
|
irc.AddCallback("NOTE", irc.handleStandardReplies)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (irc *Connection) handleRplWelcome(e Event) {
|
func (irc *Connection) handleRplWelcome(e ircmsg.Message) {
|
||||||
irc.stateMutex.Lock()
|
irc.stateMutex.Lock()
|
||||||
defer irc.stateMutex.Unlock()
|
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
|
// wake up Connect() if applicable
|
||||||
defer func() {
|
defer func() {
|
||||||
select {
|
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,
|
// only try to change the nick if we're not registered yet,
|
||||||
// otherwise we'll change in response to pingLoop unsuccessfully
|
// otherwise we'll change in response to pingLoop unsuccessfully
|
||||||
// trying to restore the intended nick (swapping one undesired nick
|
// 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()
|
irc.stateMutex.Lock()
|
||||||
defer irc.stateMutex.Unlock()
|
defer irc.stateMutex.Unlock()
|
||||||
|
|
||||||
@ -530,7 +528,7 @@ func unescapeISupportValue(in string) (out string) {
|
|||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (irc *Connection) handleCAP(e Event) {
|
func (irc *Connection) handleCAP(e ircmsg.Message) {
|
||||||
if len(e.Params) < 3 {
|
if len(e.Params) < 3 {
|
||||||
return
|
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;
|
// unconditionally print messages for FAIL and WARN;
|
||||||
// re. NOTE, if debug is enabled, we print the raw line anyway
|
// re. NOTE, if debug is enabled, we print the raw line anyway
|
||||||
switch e.Command {
|
switch e.Command {
|
||||||
|
@ -4,9 +4,11 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/goshuirc/irc-go/ircmsg"
|
||||||
)
|
)
|
||||||
|
|
||||||
func eventRewriteCTCP(event *Event) {
|
func eventRewriteCTCP(event *ircmsg.Message) {
|
||||||
// XXX rewrite event.Command for CTCP
|
// XXX rewrite event.Command for CTCP
|
||||||
if !(event.Command == "PRIVMSG" && len(event.Params) == 2 && strings.HasPrefix(event.Params[1], "\x01")) {
|
if !(event.Command == "PRIVMSG" && len(event.Params) == 2 && strings.HasPrefix(event.Params[1], "\x01")) {
|
||||||
return
|
return
|
||||||
@ -44,21 +46,23 @@ func eventRewriteCTCP(event *Event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (irc *Connection) setupCTCPCallbacks() {
|
func (irc *Connection) setupCTCPCallbacks() {
|
||||||
irc.AddCallback("CTCP_VERSION", func(e Event) {
|
irc.AddCallback("CTCP_VERSION", func(e ircmsg.Message) {
|
||||||
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01VERSION %s\x01", e.Nick(), irc.Version))
|
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01VERSION %s\x01", ExtractNick(e.Prefix), irc.Version))
|
||||||
})
|
})
|
||||||
|
|
||||||
irc.AddCallback("CTCP_USERINFO", func(e Event) {
|
irc.AddCallback("CTCP_USERINFO", func(e ircmsg.Message) {
|
||||||
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01USERINFO %s\x01", e.Nick(), irc.User))
|
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01USERINFO %s\x01", ExtractNick(e.Prefix), irc.User))
|
||||||
})
|
})
|
||||||
|
|
||||||
irc.AddCallback("CTCP_CLIENTINFO", func(e Event) {
|
irc.AddCallback("CTCP_CLIENTINFO", func(e ircmsg.Message) {
|
||||||
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01", e.Nick()))
|
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01CLIENTINFO PING VERSION TIME USERINFO CLIENTINFO\x01", ExtractNick(e.Prefix)))
|
||||||
})
|
})
|
||||||
|
|
||||||
irc.AddCallback("CTCP_TIME", func(e Event) {
|
irc.AddCallback("CTCP_TIME", func(e ircmsg.Message) {
|
||||||
irc.SendRaw(fmt.Sprintf("NOTICE %s :\x01TIME %s\x01", e.Nick(), time.Now().UTC().Format(time.RFC1123)))
|
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]))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ import (
|
|||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/goshuirc/irc-go/ircmsg"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -21,7 +23,7 @@ func TestLabeledResponse(t *testing.T) {
|
|||||||
irccon.RequestCaps = []string{"message-tags", "batch", "labeled-response"}
|
irccon.RequestCaps = []string{"message-tags", "batch", "labeled-response"}
|
||||||
irccon.RealName = "ecf61da38b58"
|
irccon.RealName = "ecf61da38b58"
|
||||||
results := make(map[string]string)
|
results := make(map[string]string)
|
||||||
irccon.AddConnectCallback(func(e Event) {
|
irccon.AddConnectCallback(func(e ircmsg.Message) {
|
||||||
irccon.SendWithLabel(func(batch *Batch) {
|
irccon.SendWithLabel(func(batch *Batch) {
|
||||||
if batch == nil {
|
if batch == nil {
|
||||||
return
|
return
|
||||||
@ -192,7 +194,7 @@ func TestBatchHandlers(t *testing.T) {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
alice.AddCallback("PRIVMSG", func(e Event) {
|
alice.AddCallback("PRIVMSG", func(e ircmsg.Message) {
|
||||||
alicePrivmsgCount++
|
alicePrivmsgCount++
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -7,16 +7,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestParse(t *testing.T) {
|
func TestParse(t *testing.T) {
|
||||||
event := new(Event)
|
source := "nick!~user@host"
|
||||||
event.Prefix = "nick!~user@host"
|
nick, user, host := SplitNUH(source)
|
||||||
|
|
||||||
if event.Nick() != "nick" {
|
if nick != "nick" {
|
||||||
t.Fatal("Parse failed: nick")
|
t.Fatal("Parse failed: nick")
|
||||||
}
|
}
|
||||||
if event.User() != "~user" {
|
if user != "~user" {
|
||||||
t.Fatal("Parse failed: user")
|
t.Fatal("Parse failed: user")
|
||||||
}
|
}
|
||||||
if event.Host() != "host" {
|
if host != "host" {
|
||||||
t.Fatal("Parse failed: host")
|
t.Fatal("Parse failed: host")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,8 @@ import (
|
|||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/goshuirc/irc-go/ircmsg"
|
||||||
)
|
)
|
||||||
|
|
||||||
type saslResult struct {
|
type saslResult struct {
|
||||||
@ -28,35 +30,35 @@ func (irc *Connection) submitSASLResult(r saslResult) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (irc *Connection) setupSASLCallbacks() {
|
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)))
|
str := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s\x00%s\x00%s", irc.SASLLogin, irc.SASLLogin, irc.SASLPassword)))
|
||||||
irc.Send("AUTHENTICATE", str)
|
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("CAP END")
|
||||||
irc.SendRaw("QUIT")
|
irc.SendRaw("QUIT")
|
||||||
irc.submitSASLResult(saslResult{true, errors.New(e.Params[1])})
|
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("CAP END")
|
||||||
irc.SendRaw("QUIT")
|
irc.SendRaw("QUIT")
|
||||||
irc.submitSASLResult(saslResult{true, errors.New(e.Params[1])})
|
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.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("CAP END")
|
||||||
irc.SendRaw("QUIT")
|
irc.SendRaw("QUIT")
|
||||||
irc.submitSASLResult(saslResult{true, errors.New(e.Params[1])})
|
irc.submitSASLResult(saslResult{true, errors.New(e.Params[1])})
|
||||||
})
|
})
|
||||||
|
|
||||||
// this could potentially happen with auto-login via certfp?
|
// 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})
|
irc.submitSASLResult(saslResult{false, nil})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/goshuirc/irc-go/ircmsg"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -48,9 +50,9 @@ func runCAPTest(caps []string, useSASL bool, t *testing.T) {
|
|||||||
}
|
}
|
||||||
irccon.RequestCaps = caps
|
irccon.RequestCaps = caps
|
||||||
irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
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.Privmsg("#go-eventirc", "Test Message SASL")
|
||||||
irccon.Quit()
|
irccon.Quit()
|
||||||
})
|
})
|
||||||
@ -96,7 +98,7 @@ func TestSASLFail(t *testing.T) {
|
|||||||
irccon.UseTLS = true
|
irccon.UseTLS = true
|
||||||
setSaslTestCreds(irccon, t)
|
setSaslTestCreds(irccon, t)
|
||||||
irccon.TLSConfig = &tls.Config{InsecureSkipVerify: true}
|
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
|
// intentionally break the password
|
||||||
irccon.SASLPassword = irccon.SASLPassword + "_"
|
irccon.SASLPassword = irccon.SASLPassword + "_"
|
||||||
err := irccon.Connect()
|
err := irccon.Connect()
|
||||||
|
@ -17,7 +17,7 @@ import (
|
|||||||
|
|
||||||
type empty struct{}
|
type empty struct{}
|
||||||
|
|
||||||
type Callback func(Event)
|
type Callback func(ircmsg.Message)
|
||||||
|
|
||||||
type callbackPair struct {
|
type callbackPair struct {
|
||||||
id uint64
|
id uint64
|
||||||
@ -65,7 +65,7 @@ type Connection struct {
|
|||||||
|
|
||||||
// networking and synchronization
|
// networking and synchronization
|
||||||
stateMutex sync.Mutex // innermost mutex: don't block while holding this
|
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
|
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
|
wg sync.WaitGroup // after closing end, wait on this for all the goroutines to stop
|
||||||
socket net.Conn
|
socket net.Conn
|
||||||
@ -123,74 +123,40 @@ type pendingLabel struct {
|
|||||||
callback LabelCallback
|
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
|
// Batch represents an IRCv3 batch, or a line within one. There are
|
||||||
// two cases:
|
// two cases:
|
||||||
// 1. (Batch).Command == "BATCH". This indicates the start of an IRCv3
|
// 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
|
// may contain tags that pertain to the batch as a whole. (Batch).Items
|
||||||
// contains zero or more *Batch elements, pointing to the contents of
|
// contains zero or more *Batch elements, pointing to the contents of
|
||||||
// the batch in order.
|
// the batch in order.
|
||||||
// 2. (Batch).Command != "BATCH". This is an ordinary IRC line; its
|
// 2. (Batch).Command != "BATCH". This is an ordinary IRC line; its
|
||||||
// tags, command, and parameters are available as members of the embedded
|
// 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`
|
// 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.
|
// value of *Batch indicates that the server failed to respond in time.
|
||||||
type Batch struct {
|
type Batch struct {
|
||||||
ircmsg.IRCMessage
|
ircmsg.Message
|
||||||
Items []*Batch
|
Items []*Batch
|
||||||
}
|
}
|
||||||
|
|
||||||
// Retrieve the last message from Event arguments.
|
func ExtractNick(source string) string {
|
||||||
// This function leaves the arguments untouched and
|
nick, _, _ := SplitNUH(source)
|
||||||
// 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()
|
|
||||||
return nick
|
return nick
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Event) User() string {
|
func SplitNUH(source string) (nick, user, host string) {
|
||||||
_, user, _ := e.splitNUH()
|
if i, j := strings.Index(source, "!"), strings.Index(source, "@"); i > -1 && j > -1 && i < j {
|
||||||
return user
|
nick = source[0:i]
|
||||||
}
|
user = source[i+1 : j]
|
||||||
|
host = source[j+1:]
|
||||||
func (e *Event) Host() string {
|
}
|
||||||
_, _, host := e.splitNUH()
|
return
|
||||||
return host
|
}
|
||||||
}
|
|
||||||
|
func lastParam(msg *ircmsg.Message) (result string) {
|
||||||
func (event *Event) splitNUH() (nick, user, host string) {
|
if 0 < len(msg.Params) {
|
||||||
if i, j := strings.Index(event.Prefix, "!"), strings.Index(event.Prefix, "@"); i > -1 && j > -1 && i < j {
|
return msg.Params[len(msg.Params)-1]
|
||||||
nick = event.Prefix[0:i]
|
|
||||||
user = event.Prefix[i+1 : j]
|
|
||||||
host = event.Prefix[j+1:]
|
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ func connForTesting(nick, user string, tls bool) *Connection {
|
|||||||
return irc
|
return irc
|
||||||
}
|
}
|
||||||
|
|
||||||
func mockEvent(command string) ircmsg.IRCMessage {
|
func mockEvent(command string) ircmsg.Message {
|
||||||
return ircmsg.MakeMessage(nil, ":server.name", command)
|
return ircmsg.MakeMessage(nil, ":server.name", command)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,9 +37,9 @@ func TestRemoveCallback(t *testing.T) {
|
|||||||
|
|
||||||
done := make(chan int, 10)
|
done := make(chan int, 10)
|
||||||
|
|
||||||
irccon.AddCallback("TEST", func(e Event) { done <- 1 })
|
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 1 })
|
||||||
id := irccon.AddCallback("TEST", func(e Event) { done <- 2 })
|
id := irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 2 })
|
||||||
irccon.AddCallback("TEST", func(e Event) { done <- 3 })
|
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 3 })
|
||||||
|
|
||||||
// Should remove callback at index 1
|
// Should remove callback at index 1
|
||||||
irccon.RemoveCallback(id)
|
irccon.RemoveCallback(id)
|
||||||
@ -62,11 +62,11 @@ func TestClearCallback(t *testing.T) {
|
|||||||
|
|
||||||
done := make(chan int, 10)
|
done := make(chan int, 10)
|
||||||
|
|
||||||
irccon.AddCallback("TEST", func(e Event) { done <- 0 })
|
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 0 })
|
||||||
irccon.AddCallback("TEST", func(e Event) { done <- 1 })
|
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 1 })
|
||||||
irccon.ClearCallback("TEST")
|
irccon.ClearCallback("TEST")
|
||||||
irccon.AddCallback("TEST", func(e Event) { done <- 2 })
|
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 2 })
|
||||||
irccon.AddCallback("TEST", func(e Event) { done <- 3 })
|
irccon.AddCallback("TEST", func(e ircmsg.Message) { done <- 3 })
|
||||||
|
|
||||||
irccon.runCallbacks(mockEvent("TEST"))
|
irccon.runCallbacks(mockEvent("TEST"))
|
||||||
|
|
||||||
@ -106,10 +106,10 @@ func TestConnection(t *testing.T) {
|
|||||||
teststr := randStr(20)
|
teststr := randStr(20)
|
||||||
testmsgok := make(chan bool, 1)
|
testmsgok := make(chan bool, 1)
|
||||||
|
|
||||||
irccon1.AddCallback("001", func(e Event) { irccon1.Join(channel) })
|
irccon1.AddCallback("001", func(e ircmsg.Message) { irccon1.Join(channel) })
|
||||||
irccon2.AddCallback("001", func(e Event) { irccon2.Join(channel) })
|
irccon2.AddCallback("001", func(e ircmsg.Message) { irccon2.Join(channel) })
|
||||||
irccon1.AddCallback("366", func(e Event) {
|
irccon1.AddCallback("366", func(e ircmsg.Message) {
|
||||||
go func(e Event) {
|
go func(e ircmsg.Message) {
|
||||||
tick := time.NewTicker(1 * time.Second)
|
tick := time.NewTicker(1 * time.Second)
|
||||||
i := 10
|
i := 10
|
||||||
for {
|
for {
|
||||||
@ -131,14 +131,14 @@ func TestConnection(t *testing.T) {
|
|||||||
}(e)
|
}(e)
|
||||||
})
|
})
|
||||||
|
|
||||||
irccon2.AddCallback("366", func(e Event) {
|
irccon2.AddCallback("366", func(e ircmsg.Message) {
|
||||||
ircnick2 = randStr(8)
|
ircnick2 = randStr(8)
|
||||||
irccon2.SetNick(ircnick2)
|
irccon2.SetNick(ircnick2)
|
||||||
})
|
})
|
||||||
|
|
||||||
irccon2.AddCallback("PRIVMSG", func(e Event) {
|
irccon2.AddCallback("PRIVMSG", func(e ircmsg.Message) {
|
||||||
if e.Message() == teststr {
|
if e.Params[1] == teststr {
|
||||||
if e.Nick() == ircnick1 {
|
if ExtractNick(e.Prefix) == ircnick1 {
|
||||||
testmsgok <- true
|
testmsgok <- true
|
||||||
irccon2.Quit()
|
irccon2.Quit()
|
||||||
} else {
|
} else {
|
||||||
@ -150,8 +150,8 @@ func TestConnection(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
irccon2.AddCallback("NICK", func(e Event) {
|
irccon2.AddCallback("NICK", func(e ircmsg.Message) {
|
||||||
if !(e.Nick() == ircnick2orig && e.Message() == ircnick2) {
|
if !(ExtractNick(e.Prefix) == ircnick2orig && e.Params[0] == ircnick2) {
|
||||||
t.Errorf("Nick change did not work!")
|
t.Errorf("Nick change did not work!")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -181,9 +181,9 @@ func runReconnectTest(useSASL bool, t *testing.T) {
|
|||||||
debugTest(irccon)
|
debugTest(irccon)
|
||||||
|
|
||||||
connects := 0
|
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
|
connects += 1
|
||||||
if connects > 2 {
|
if connects > 2 {
|
||||||
irccon.Privmsgf(channel, "Connection nr %d (test done)", connects)
|
irccon.Privmsgf(channel, "Connection nr %d (test done)", connects)
|
||||||
@ -226,9 +226,9 @@ func TestConnectionSSL(t *testing.T) {
|
|||||||
debugTest(irccon)
|
debugTest(irccon)
|
||||||
irccon.UseTLS = true
|
irccon.UseTLS = true
|
||||||
irccon.TLSConfig = &tls.Config{InsecureSkipVerify: 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.Privmsg(channel, "Test Message from SSL")
|
||||||
irccon.Quit()
|
irccon.Quit()
|
||||||
})
|
})
|
||||||
@ -284,8 +284,8 @@ func TestConnectionNickInUse(t *testing.T) {
|
|||||||
n2 := make(chan string, 1)
|
n2 := make(chan string, 1)
|
||||||
|
|
||||||
// check the actual nick after 001 is processed
|
// check the actual nick after 001 is processed
|
||||||
irccon1.AddCallback("002", func(e Event) { n1 <- irccon1.CurrentNick() })
|
irccon1.AddCallback("002", func(e ircmsg.Message) { n1 <- irccon1.CurrentNick() })
|
||||||
irccon2.AddCallback("002", func(e Event) { n2 <- irccon2.CurrentNick() })
|
irccon2.AddCallback("002", func(e ircmsg.Message) { n2 <- irccon2.CurrentNick() })
|
||||||
|
|
||||||
err := irccon1.Connect()
|
err := irccon1.Connect()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -318,7 +318,7 @@ func TestConnectionCallbacks(t *testing.T) {
|
|||||||
irccon1 := connForTesting(ircnick, "IRCTest1", false)
|
irccon1 := connForTesting(ircnick, "IRCTest1", false)
|
||||||
debugTest(irccon1)
|
debugTest(irccon1)
|
||||||
resultChan := make(chan map[string]string, 1)
|
resultChan := make(chan map[string]string, 1)
|
||||||
irccon1.AddConnectCallback(func(e Event) {
|
irccon1.AddConnectCallback(func(e ircmsg.Message) {
|
||||||
resultChan <- irccon1.ISupport()
|
resultChan <- irccon1.ISupport()
|
||||||
})
|
})
|
||||||
err := irccon1.Connect()
|
err := irccon1.Connect()
|
||||||
|
@ -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")
|
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
|
// extended by the IRCv3 Message Tags specification with the introduction
|
||||||
// of message tags.
|
// of message tags.
|
||||||
type IRCMessage struct {
|
type Message struct {
|
||||||
Prefix string
|
Prefix string
|
||||||
Command string
|
Command string
|
||||||
Params []string
|
Params []string
|
||||||
@ -77,12 +77,12 @@ type IRCMessage struct {
|
|||||||
// will be encoded as a "trailing parameter" (preceded by a colon). This is
|
// 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
|
// almost never necessary and should not be used except when having to interact
|
||||||
// with broken implementations that don't correctly interpret IRC messages.
|
// with broken implementations that don't correctly interpret IRC messages.
|
||||||
func (msg *IRCMessage) ForceTrailing() {
|
func (msg *Message) ForceTrailing() {
|
||||||
msg.forceTrailing = true
|
msg.forceTrailing = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetTag returns whether a tag is present, and if so, what its value is.
|
// 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 {
|
if len(tagName) == 0 {
|
||||||
return
|
return
|
||||||
} else if tagName[0] == '+' {
|
} 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.
|
// 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)
|
present, _ = msg.GetTag(tagName)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTag sets a tag.
|
// SetTag sets a tag.
|
||||||
func (msg *IRCMessage) SetTag(tagName, tagValue string) {
|
func (msg *Message) SetTag(tagName, tagValue string) {
|
||||||
if len(tagName) == 0 {
|
if len(tagName) == 0 {
|
||||||
return
|
return
|
||||||
} else if tagName[0] == '+' {
|
} else if tagName[0] == '+' {
|
||||||
@ -118,7 +118,7 @@ func (msg *IRCMessage) SetTag(tagName, tagValue string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DeleteTag deletes a tag.
|
// DeleteTag deletes a tag.
|
||||||
func (msg *IRCMessage) DeleteTag(tagName string) {
|
func (msg *Message) DeleteTag(tagName string) {
|
||||||
if len(tagName) == 0 {
|
if len(tagName) == 0 {
|
||||||
return
|
return
|
||||||
} else if tagName[0] == '+' {
|
} else if tagName[0] == '+' {
|
||||||
@ -129,14 +129,14 @@ func (msg *IRCMessage) DeleteTag(tagName string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateTags is a convenience to set multiple tags at once.
|
// 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 {
|
for name, value := range tags {
|
||||||
msg.SetTag(name, value)
|
msg.SetTag(name, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AllTags returns all tags as a single map.
|
// 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))
|
result = make(map[string]string, len(msg.tags)+len(msg.clientOnlyTags))
|
||||||
for name, value := range msg.tags {
|
for name, value := range msg.tags {
|
||||||
result[name] = value
|
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).
|
// 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.
|
// should not be modified.
|
||||||
func (msg *IRCMessage) ClientOnlyTags() map[string]string {
|
func (msg *Message) ClientOnlyTags() map[string]string {
|
||||||
return msg.clientOnlyTags
|
return msg.clientOnlyTags
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParseLine creates and returns a message from the given IRC line.
|
// 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)
|
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.
|
// 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),
|
// 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
|
// 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.
|
// 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
|
maxTagDataLength := MaxlenTagData
|
||||||
if fromClient {
|
if fromClient {
|
||||||
maxTagDataLength = MaxlenClientTagData
|
maxTagDataLength = MaxlenClientTagData
|
||||||
@ -180,7 +180,7 @@ func trimInitialSpaces(str string) string {
|
|||||||
return str[i:]
|
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:
|
// remove either \n or \r\n from the end of the line:
|
||||||
line = strings.TrimSuffix(line, "\n")
|
line = strings.TrimSuffix(line, "\n")
|
||||||
line = strings.TrimSuffix(line, "\r")
|
line = strings.TrimSuffix(line, "\r")
|
||||||
@ -279,7 +279,7 @@ func parseLine(line string, maxTagDataLength int, truncateLen int) (ircmsg IRCMe
|
|||||||
}
|
}
|
||||||
|
|
||||||
// helper to parse tags
|
// helper to parse tags
|
||||||
func (ircmsg *IRCMessage) parseTags(tags string) (err error) {
|
func (ircmsg *Message) parseTags(tags string) (err error) {
|
||||||
for 0 < len(tags) {
|
for 0 < len(tags) {
|
||||||
tagEnd := strings.IndexByte(tags, ';')
|
tagEnd := strings.IndexByte(tags, ';')
|
||||||
endPos := tagEnd
|
endPos := tagEnd
|
||||||
@ -311,8 +311,8 @@ func (ircmsg *IRCMessage) parseTags(tags string) (err error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeMessage provides a simple way to create a new IRCMessage.
|
// MakeMessage provides a simple way to create a new Message.
|
||||||
func MakeMessage(tags map[string]string, prefix string, command string, params ...string) (ircmsg IRCMessage) {
|
func MakeMessage(tags map[string]string, prefix string, command string, params ...string) (ircmsg Message) {
|
||||||
ircmsg.Prefix = prefix
|
ircmsg.Prefix = prefix
|
||||||
ircmsg.Command = command
|
ircmsg.Command = command
|
||||||
ircmsg.Params = params
|
ircmsg.Params = params
|
||||||
@ -320,8 +320,8 @@ func MakeMessage(tags map[string]string, prefix string, command string, params .
|
|||||||
return ircmsg
|
return ircmsg
|
||||||
}
|
}
|
||||||
|
|
||||||
// Line returns a sendable line created from an IRCMessage.
|
// Line returns a sendable line created from an Message.
|
||||||
func (ircmsg *IRCMessage) Line() (result string, err error) {
|
func (ircmsg *Message) Line() (result string, err error) {
|
||||||
bytes, err := ircmsg.line(0, 0, 0, 0)
|
bytes, err := ircmsg.line(0, 0, 0, 0)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
result = string(bytes)
|
result = string(bytes)
|
||||||
@ -329,17 +329,17 @@ func (ircmsg *IRCMessage) Line() (result string, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// LineBytes returns a sendable line created from an IRCMessage.
|
// LineBytes returns a sendable line created from an Message.
|
||||||
func (ircmsg *IRCMessage) LineBytes() (result []byte, err error) {
|
func (ircmsg *Message) LineBytes() (result []byte, err error) {
|
||||||
result, err = ircmsg.line(0, 0, 0, 0)
|
result, err = ircmsg.line(0, 0, 0, 0)
|
||||||
return
|
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
|
// 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
|
// is enforced. If truncateLen is nonzero, it is the length at which the
|
||||||
// non-tag portion of the message is truncated.
|
// 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
|
var tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit int
|
||||||
if fromClient {
|
if fromClient {
|
||||||
// enforce client max tags:
|
// enforce client max tags:
|
||||||
@ -359,8 +359,8 @@ func paramRequiresTrailing(param string) bool {
|
|||||||
return len(param) == 0 || strings.IndexByte(param, ' ') != -1 || param[0] == ':'
|
return len(param) == 0 || strings.IndexByte(param, ' ') != -1 || param[0] == ':'
|
||||||
}
|
}
|
||||||
|
|
||||||
// line returns a sendable line created from an IRCMessage.
|
// line returns a sendable line created from an Message.
|
||||||
func (ircmsg *IRCMessage) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) (result []byte, err error) {
|
func (ircmsg *Message) line(tagLimit, clientOnlyTagDataLimit, serverAddedTagDataLimit, truncateLen int) (result []byte, err error) {
|
||||||
if len(ircmsg.Command) == 0 {
|
if len(ircmsg.Command) == 0 {
|
||||||
return nil, ErrorCommandMissing
|
return nil, ErrorCommandMissing
|
||||||
}
|
}
|
||||||
|
@ -11,12 +11,12 @@ import (
|
|||||||
|
|
||||||
type testcode struct {
|
type testcode struct {
|
||||||
raw string
|
raw string
|
||||||
message IRCMessage
|
message Message
|
||||||
}
|
}
|
||||||
type testcodewithlen struct {
|
type testcodewithlen struct {
|
||||||
raw string
|
raw string
|
||||||
length int
|
length int
|
||||||
message IRCMessage
|
message Message
|
||||||
truncateExpected bool
|
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-"},
|
tags: map[string]string{"time": "2019-02-27T04:38:57.489Z", "account": "dan-"},
|
||||||
clientOnlyTags: map[string]string{"+status": "typing"},
|
clientOnlyTags: map[string]string{"+status": "typing"},
|
||||||
@ -329,7 +329,7 @@ func TestEncodeDecode(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestForceTrailing(t *testing.T) {
|
func TestForceTrailing(t *testing.T) {
|
||||||
message := IRCMessage{
|
message := Message{
|
||||||
Prefix: "shivaram",
|
Prefix: "shivaram",
|
||||||
Command: "PRIVMSG",
|
Command: "PRIVMSG",
|
||||||
Params: []string{"#darwin", "nice"},
|
Params: []string{"#darwin", "nice"},
|
||||||
@ -352,7 +352,7 @@ func TestForceTrailing(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestErrorLineTooLongGeneration(t *testing.T) {
|
func TestErrorLineTooLongGeneration(t *testing.T) {
|
||||||
message := IRCMessage{
|
message := Message{
|
||||||
tags: map[string]string{"draft/msgid": "SAXV5OYJUr18CNJzdWa1qQ"},
|
tags: map[string]string{"draft/msgid": "SAXV5OYJUr18CNJzdWa1qQ"},
|
||||||
Prefix: "shivaram",
|
Prefix: "shivaram",
|
||||||
Command: "PRIVMSG",
|
Command: "PRIVMSG",
|
||||||
|
@ -30,7 +30,7 @@ func init() {
|
|||||||
// EscapeTagValue takes a value, and returns an escaped message tag value.
|
// EscapeTagValue takes a value, and returns an escaped message tag value.
|
||||||
//
|
//
|
||||||
// This function is automatically used when lines are created from an
|
// 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 {
|
func EscapeTagValue(inString string) string {
|
||||||
return valtoescape.Replace(inString)
|
return valtoescape.Replace(inString)
|
||||||
}
|
}
|
||||||
|
@ -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
|
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
|
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,
|
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)")
|
ErrReadQ = errors.New("readQ exceeded (read too many bytes without terminating newline)")
|
||||||
)
|
)
|
||||||
|
|
||||||
type IRCReader struct {
|
type Reader struct {
|
||||||
conn io.Reader
|
conn io.Reader
|
||||||
|
|
||||||
initialSize int
|
initialSize int
|
||||||
@ -34,17 +34,17 @@ type IRCReader struct {
|
|||||||
eof bool
|
eof bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a new *IRCReader with sane buffer size limits.
|
// Returns a new *Reader with sane buffer size limits.
|
||||||
func NewIRCReader(conn io.Reader) *IRCReader {
|
func NewIRCReader(conn io.Reader) *Reader {
|
||||||
var reader IRCReader
|
var reader Reader
|
||||||
reader.Initialize(conn, 512, 8192+1024)
|
reader.Initialize(conn, 512, 8192+1024)
|
||||||
return &reader
|
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.
|
// limits.
|
||||||
func (cc *IRCReader) Initialize(conn io.Reader, initialSize, maxSize int) {
|
func (cc *Reader) Initialize(conn io.Reader, initialSize, maxSize int) {
|
||||||
*cc = IRCReader{}
|
*cc = Reader{}
|
||||||
cc.conn = conn
|
cc.conn = conn
|
||||||
cc.initialSize = initialSize
|
cc.initialSize = initialSize
|
||||||
cc.maxSize = maxSize
|
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
|
// 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
|
// errors from the underlying connection. Returns ErrReadQ if the buffer limit
|
||||||
// was exceeded without a terminating \n.
|
// was exceeded without a terminating \n.
|
||||||
func (cc *IRCReader) ReadLine() ([]byte, error) {
|
func (cc *Reader) ReadLine() ([]byte, error) {
|
||||||
for {
|
for {
|
||||||
// try to find a terminated line in the buffered data already read
|
// try to find a terminated line in the buffered data already read
|
||||||
nlidx := bytes.IndexByte(cc.buf[cc.searchFrom:cc.end], '\n')
|
nlidx := bytes.IndexByte(cc.buf[cc.searchFrom:cc.end], '\n')
|
||||||
|
@ -158,7 +158,7 @@ func TestRegression(t *testing.T) {
|
|||||||
// this terminates the previous read, within the acceptable limit:
|
// this terminates the previous read, within the acceptable limit:
|
||||||
c.reads = append(c.reads, makeLine(500, true))
|
c.reads = append(c.reads, makeLine(500, true))
|
||||||
|
|
||||||
var cc IRCReader
|
var cc Reader
|
||||||
cc.Initialize(&c, 512, 4096+512)
|
cc.Initialize(&c, 512, 4096+512)
|
||||||
|
|
||||||
line, err := cc.ReadLine()
|
line, err := cc.ReadLine()
|
||||||
|
Loading…
Reference in New Issue
Block a user