commit
ceacb7cda1
@ -1,11 +1,11 @@
|
|||||||
Description
|
Description
|
||||||
----------
|
-----------
|
||||||
|
|
||||||
Event based irc client library.
|
Event based irc client library.
|
||||||
|
|
||||||
|
|
||||||
Features
|
Features
|
||||||
---------
|
--------
|
||||||
* Event based. Register Callbacks for the events you need to handle.
|
* Event based. Register Callbacks for the events you need to handle.
|
||||||
* Handles basic irc demands for you
|
* Handles basic irc demands for you
|
||||||
* Standard CTCP
|
* Standard CTCP
|
||||||
@ -13,15 +13,15 @@ Features
|
|||||||
* Detect stoned servers
|
* Detect stoned servers
|
||||||
|
|
||||||
Install
|
Install
|
||||||
----------
|
-------
|
||||||
$ go get github.com/thoj/go-ircevent
|
$ go get github.com/thoj/go-ircevent
|
||||||
|
|
||||||
Example
|
Example
|
||||||
----------
|
-------
|
||||||
See test/irc_test.go
|
See test/irc_test.go
|
||||||
|
|
||||||
Events for callbacks
|
Events for callbacks
|
||||||
---------
|
--------------------
|
||||||
* 001 Welcome
|
* 001 Welcome
|
||||||
* PING
|
* PING
|
||||||
* CTCP Unknown CTCP
|
* CTCP Unknown CTCP
|
||||||
@ -39,7 +39,7 @@ Events for callbacks
|
|||||||
|
|
||||||
|
|
||||||
AddCallback Example
|
AddCallback Example
|
||||||
---------
|
-------------------
|
||||||
ircobj.AddCallback("PRIVMSG", func(event *irc.Event) {
|
ircobj.AddCallback("PRIVMSG", func(event *irc.Event) {
|
||||||
//e.Message() contains the message
|
//e.Message() contains the message
|
||||||
//e.Nick Contains the sender
|
//e.Nick Contains the sender
|
||||||
|
74
irc.go
74
irc.go
@ -2,6 +2,20 @@
|
|||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
/*
|
||||||
|
This package provides an event based IRC client library. It allows to
|
||||||
|
register callbacks for the events you need to handle. Its features
|
||||||
|
include handling standard CTCP, reconnecting on errors and detecting
|
||||||
|
stones servers.
|
||||||
|
Details of the IRC protocol can be found in the following RFCs:
|
||||||
|
https://tools.ietf.org/html/rfc1459
|
||||||
|
https://tools.ietf.org/html/rfc2810
|
||||||
|
https://tools.ietf.org/html/rfc2811
|
||||||
|
https://tools.ietf.org/html/rfc2812
|
||||||
|
https://tools.ietf.org/html/rfc2813
|
||||||
|
The details of the client-to-client protocol (CTCP) can be found here: http://www.irchelp.org/irchelp/rfc/ctcpspec.html
|
||||||
|
*/
|
||||||
|
|
||||||
package irc
|
package irc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -20,6 +34,8 @@ const (
|
|||||||
VERSION = "go-ircevent v2.1"
|
VERSION = "go-ircevent v2.1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// Read data from a connection. To be used as a goroutine.
|
||||||
func (irc *Connection) readLoop() {
|
func (irc *Connection) readLoop() {
|
||||||
br := bufio.NewReaderSize(irc.socket, 512)
|
br := bufio.NewReaderSize(irc.socket, 512)
|
||||||
|
|
||||||
@ -85,6 +101,8 @@ func (irc *Connection) readLoop() {
|
|||||||
irc.readerExit <- true
|
irc.readerExit <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Loop to write to a connection. To be used as a goroutine.
|
||||||
func (irc *Connection) writeLoop() {
|
func (irc *Connection) writeLoop() {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@ -121,7 +139,9 @@ func (irc *Connection) writeLoop() {
|
|||||||
irc.writerExit <- true
|
irc.writerExit <- true
|
||||||
}
|
}
|
||||||
|
|
||||||
//Pings the server if we have not received any messages for 5 minutes
|
|
||||||
|
// Pings the server if we have not received any messages for 5 minutes
|
||||||
|
// to keep the connection alive. To be used as a goroutine.
|
||||||
func (irc *Connection) pingLoop() {
|
func (irc *Connection) pingLoop() {
|
||||||
ticker := time.NewTicker(1 * time.Minute) // Tick every minute for monitoring
|
ticker := time.NewTicker(1 * time.Minute) // Tick every minute for monitoring
|
||||||
ticker2 := time.NewTicker(irc.PingFreq) // Tick at the ping frequency.
|
ticker2 := time.NewTicker(irc.PingFreq) // Tick at the ping frequency.
|
||||||
@ -149,6 +169,8 @@ func (irc *Connection) pingLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Main loop to control the connection.
|
||||||
func (irc *Connection) Loop() {
|
func (irc *Connection) Loop() {
|
||||||
for !irc.stopped {
|
for !irc.stopped {
|
||||||
err := <-irc.Error
|
err := <-irc.Error
|
||||||
@ -168,61 +190,99 @@ func (irc *Connection) Loop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Quit the current connection and disconnect from the server
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1.6
|
||||||
func (irc *Connection) Quit() {
|
func (irc *Connection) Quit() {
|
||||||
irc.SendRaw("QUIT")
|
irc.SendRaw("QUIT")
|
||||||
irc.stopped = true
|
irc.stopped = true
|
||||||
irc.Disconnect()
|
irc.Disconnect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Use the connection to join a given channel.
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.1
|
||||||
func (irc *Connection) Join(channel string) {
|
func (irc *Connection) Join(channel string) {
|
||||||
irc.pwrite <- fmt.Sprintf("JOIN %s\r\n", channel)
|
irc.pwrite <- fmt.Sprintf("JOIN %s\r\n", channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Leave a given channel.
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.2
|
||||||
func (irc *Connection) Part(channel string) {
|
func (irc *Connection) Part(channel string) {
|
||||||
irc.pwrite <- fmt.Sprintf("PART %s\r\n", channel)
|
irc.pwrite <- fmt.Sprintf("PART %s\r\n", channel)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send a notification to a nickname. This is similar to Privmsg but must not receive replies.
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.2
|
||||||
func (irc *Connection) Notice(target, message string) {
|
func (irc *Connection) Notice(target, message string) {
|
||||||
irc.pwrite <- fmt.Sprintf("NOTICE %s :%s\r\n", target, message)
|
irc.pwrite <- fmt.Sprintf("NOTICE %s :%s\r\n", target, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send a formated notification to a nickname.
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.2
|
||||||
func (irc *Connection) Noticef(target, format string, a ...interface{}) {
|
func (irc *Connection) Noticef(target, format string, a ...interface{}) {
|
||||||
irc.Notice(target, fmt.Sprintf(format, a...))
|
irc.Notice(target, fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send (private) message to a target (channel or nickname).
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.4.1
|
||||||
func (irc *Connection) Privmsg(target, message string) {
|
func (irc *Connection) Privmsg(target, message string) {
|
||||||
irc.pwrite <- fmt.Sprintf("PRIVMSG %s :%s\r\n", target, message)
|
irc.pwrite <- fmt.Sprintf("PRIVMSG %s :%s\r\n", target, message)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send formated string to specified target (channel or nickname).
|
||||||
func (irc *Connection) Privmsgf(target, format string, a ...interface{}) {
|
func (irc *Connection) Privmsgf(target, format string, a ...interface{}) {
|
||||||
irc.Privmsg(target, fmt.Sprintf(format, a...))
|
irc.Privmsg(target, fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send raw string.
|
||||||
func (irc *Connection) SendRaw(message string) {
|
func (irc *Connection) SendRaw(message string) {
|
||||||
irc.pwrite <- message + "\r\n"
|
irc.pwrite <- message + "\r\n"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Send raw formated string.
|
||||||
func (irc *Connection) SendRawf(format string, a ...interface{}) {
|
func (irc *Connection) SendRawf(format string, a ...interface{}) {
|
||||||
irc.SendRaw(fmt.Sprintf(format, a...))
|
irc.SendRaw(fmt.Sprintf(format, a...))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set (new) nickname.
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1.2
|
||||||
func (irc *Connection) Nick(n string) {
|
func (irc *Connection) Nick(n string) {
|
||||||
irc.nick = n
|
irc.nick = n
|
||||||
irc.SendRawf("NICK %s", n)
|
irc.SendRawf("NICK %s", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Determine nick currently used with the connection.
|
||||||
func (irc *Connection) GetNick() string {
|
func (irc *Connection) GetNick() string {
|
||||||
return irc.nickcurrent
|
return irc.nickcurrent
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Query information about a particular nickname.
|
||||||
|
// RFC 1459: https://tools.ietf.org/html/rfc1459#section-4.5.2
|
||||||
func (irc *Connection) Whois(nick string) {
|
func (irc *Connection) Whois(nick string) {
|
||||||
irc.SendRawf("WHOIS %s", nick)
|
irc.SendRawf("WHOIS %s", nick)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Query information about a given nickname in the server.
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.5.1
|
||||||
func (irc *Connection) Who(nick string) {
|
func (irc *Connection) Who(nick string) {
|
||||||
irc.SendRawf("WHO %s", nick)
|
irc.SendRawf("WHO %s", nick)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set different modes for a target (channel or nickname).
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.2.3
|
||||||
func (irc *Connection) Mode(target string, modestring ...string) {
|
func (irc *Connection) Mode(target string, modestring ...string) {
|
||||||
if len(modestring) > 0 {
|
if len(modestring) > 0 {
|
||||||
mode := strings.Join(modestring, " ")
|
mode := strings.Join(modestring, " ")
|
||||||
@ -232,7 +292,8 @@ func (irc *Connection) Mode(target string, modestring ...string) {
|
|||||||
irc.SendRawf("MODE %s", target)
|
irc.SendRawf("MODE %s", target)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends all buffered messages (if possible),
|
|
||||||
|
// A disconnect sends all buffered messages (if possible),
|
||||||
// stops all goroutines and then closes the socket.
|
// stops all goroutines and then closes the socket.
|
||||||
func (irc *Connection) Disconnect() {
|
func (irc *Connection) Disconnect() {
|
||||||
irc.endping <- true
|
irc.endping <- true
|
||||||
@ -253,10 +314,16 @@ func (irc *Connection) Disconnect() {
|
|||||||
irc.Error <- errors.New("Disconnect Called")
|
irc.Error <- errors.New("Disconnect Called")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Reconnect to a server using the current connection.
|
||||||
func (irc *Connection) Reconnect() error {
|
func (irc *Connection) Reconnect() error {
|
||||||
return irc.Connect(irc.server)
|
return irc.Connect(irc.server)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Connect to a given server using the current connection configuration.
|
||||||
|
// This function also takes care of identification if a password is provided.
|
||||||
|
// RFC 1459 details: https://tools.ietf.org/html/rfc1459#section-4.1
|
||||||
func (irc *Connection) Connect(server string) error {
|
func (irc *Connection) Connect(server string) error {
|
||||||
irc.server = server
|
irc.server = server
|
||||||
irc.stopped = false
|
irc.stopped = false
|
||||||
@ -290,6 +357,9 @@ func (irc *Connection) Connect(server string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create a connection with the (publicly visible) nickname and username.
|
||||||
|
// The nickname is later used to address the user.
|
||||||
func IRC(nick, user string) *Connection {
|
func IRC(nick, user string) *Connection {
|
||||||
irc := &Connection{
|
irc := &Connection{
|
||||||
nick: nick,
|
nick: nick,
|
||||||
|
@ -10,6 +10,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
// Register a callback to a connection and event code. A callback is a function
|
||||||
|
// which takes only an Event pointer 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)) string {
|
func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) string {
|
||||||
eventcode = strings.ToUpper(eventcode)
|
eventcode = strings.ToUpper(eventcode)
|
||||||
|
|
||||||
@ -24,6 +29,9 @@ func (irc *Connection) AddCallback(eventcode string, callback func(*Event)) stri
|
|||||||
return id
|
return id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove callback i (ID) from the given event code. This functions returns
|
||||||
|
// true upon success, false if any error occurs.
|
||||||
func (irc *Connection) RemoveCallback(eventcode string, i string) bool {
|
func (irc *Connection) RemoveCallback(eventcode string, i string) bool {
|
||||||
eventcode = strings.ToUpper(eventcode)
|
eventcode = strings.ToUpper(eventcode)
|
||||||
|
|
||||||
@ -40,6 +48,9 @@ func (irc *Connection) RemoveCallback(eventcode string, i string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Remove all callbacks from a given event code. It returns true
|
||||||
|
// if given event code is found and cleared.
|
||||||
func (irc *Connection) ClearCallback(eventcode string) bool {
|
func (irc *Connection) ClearCallback(eventcode string) bool {
|
||||||
eventcode = strings.ToUpper(eventcode)
|
eventcode = strings.ToUpper(eventcode)
|
||||||
|
|
||||||
@ -52,6 +63,8 @@ func (irc *Connection) ClearCallback(eventcode string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Replace callback i (ID) associated with a given event code with a new callback function.
|
||||||
func (irc *Connection) ReplaceCallback(eventcode string, i string, callback func(*Event)) {
|
func (irc *Connection) ReplaceCallback(eventcode string, i string, callback func(*Event)) {
|
||||||
eventcode = strings.ToUpper(eventcode)
|
eventcode = strings.ToUpper(eventcode)
|
||||||
|
|
||||||
@ -65,6 +78,8 @@ func (irc *Connection) ReplaceCallback(eventcode string, i string, callback func
|
|||||||
irc.Log.Printf("Event not found. Use AddCallBack\n")
|
irc.Log.Printf("Event not found. Use AddCallBack\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Execute all callbacks associated with a given event.
|
||||||
func (irc *Connection) RunCallbacks(event *Event) {
|
func (irc *Connection) RunCallbacks(event *Event) {
|
||||||
msg := event.Message()
|
msg := event.Message()
|
||||||
if event.Code == "PRIVMSG" && len(msg) > 0 && msg[0] == '\x01' {
|
if event.Code == "PRIVMSG" && len(msg) > 0 && msg[0] == '\x01' {
|
||||||
@ -119,6 +134,8 @@ func (irc *Connection) RunCallbacks(event *Event) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set up some initial callbacks to handle the IRC/CTCP protocol.
|
||||||
func (irc *Connection) setupCallbacks() {
|
func (irc *Connection) setupCallbacks() {
|
||||||
irc.events = make(map[string]map[string]func(*Event))
|
irc.events = make(map[string]map[string]func(*Event))
|
||||||
|
|
||||||
|
@ -43,6 +43,8 @@ type Connection struct {
|
|||||||
stopped bool
|
stopped bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// A struct to represent an event.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
Code string
|
Code string
|
||||||
Raw string
|
Raw string
|
||||||
@ -53,7 +55,10 @@ type Event struct {
|
|||||||
Arguments []string
|
Arguments []string
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience func to get the last arg, now that the Message field is gone
|
|
||||||
|
// 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 {
|
func (e *Event) Message() string {
|
||||||
if len(e.Arguments) == 0 {
|
if len(e.Arguments) == 0 {
|
||||||
return ""
|
return ""
|
||||||
|
Loading…
Reference in New Issue
Block a user