Merge pull request #26 from tpltnt/more-docs

More docs
This commit is contained in:
Thomas Jager 2014-02-14 18:15:14 +01:00
commit ceacb7cda1
4 changed files with 101 additions and 9 deletions

View File

@ -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
View File

@ -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,

View File

@ -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))

View File

@ -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 ""