Merge pull request #15 from Philipp15b/improvements

Some improvements
This commit is contained in:
Thomas Jager 2013-04-04 07:47:20 -07:00
commit 14b5cb8b16
2 changed files with 64 additions and 94 deletions

150
irc.go
View File

@ -16,11 +16,11 @@ import (
) )
const ( const (
VERSION = "go-ircevent v2.0" VERSION = "go-ircevent v2.1"
) )
func (irc *Connection) readLoop() { func (irc *Connection) readLoop() {
br := bufio.NewReader(irc.socket) br := bufio.NewReaderSize(irc.socket, 512)
for { for {
msg, err := br.ReadString('\n') msg, err := br.ReadString('\n')
@ -30,7 +30,7 @@ func (irc *Connection) readLoop() {
} }
irc.lastMessage = time.Now() irc.lastMessage = time.Now()
msg = msg[0 : len(msg)-2] //Remove \r\n msg = msg[:len(msg)-2] //Remove \r\n
event := &Event{Raw: msg} event := &Event{Raw: msg}
if msg[0] == ':' { if msg[0] == ':' {
if i := strings.Index(msg, " "); i > -1 { if i := strings.Index(msg, " "); i > -1 {
@ -64,40 +64,38 @@ func (irc *Connection) readLoop() {
irc.RunCallbacks(event) irc.RunCallbacks(event)
} }
irc.syncreader <- true irc.readerExit <- true
} }
func (irc *Connection) writeLoop() { func (irc *Connection) writeLoop() {
b, ok := <-irc.pwrite for {
for ok { b, ok := <-irc.pwrite
if b == "" || irc.socket == nil { if !ok || b == "" || irc.socket == nil {
break
}
irc.log.Printf("--> %s\n", b)
_, err := irc.socket.Write([]byte(b))
if err != nil {
irc.log.Printf("%s\n", err)
irc.Error <- err
break break
} }
b, ok = <-irc.pwrite irc.log.Printf("--> %s\n", b)
_, err := irc.socket.Write([]byte(b))
if err != nil {
irc.Error <- err
break
}
} }
irc.syncwriter <- true irc.writerExit <- true
} }
//Pings the server if we have not recived any messages for 5 minutes //Pings the server if we have not recived any messages for 5 minutes
func (irc *Connection) pingLoop() { func (irc *Connection) pingLoop() {
irc.ticker = time.NewTicker(1 * time.Minute) //Tick every minute. ticker := time.NewTicker(1 * time.Minute) //Tick every minute.
irc.ticker2 = time.NewTicker(15 * time.Minute) //Tick every 15 minutes. ticker2 := time.NewTicker(15 * time.Minute) //Tick every 15 minutes.
for { for {
select { select {
case <-irc.ticker.C: case <-ticker.C:
//Ping if we haven't recived anything from the server within 4 minutes //Ping if we haven't received anything from the server within 4 minutes
if time.Since(irc.lastMessage) >= (4 * time.Minute) { if time.Since(irc.lastMessage) >= (4 * time.Minute) {
irc.SendRawf("PING %d", time.Now().UnixNano()) irc.SendRawf("PING %d", time.Now().UnixNano())
} }
case <-irc.ticker2.C: case <-ticker2.C:
//Ping every 15 minutes. //Ping every 15 minutes.
irc.SendRawf("PING %d", time.Now().UnixNano()) irc.SendRawf("PING %d", time.Now().UnixNano())
//Try to recapture nickname if it's not as configured. //Try to recapture nickname if it's not as configured.
@ -106,22 +104,30 @@ func (irc *Connection) pingLoop() {
irc.SendRawf("NICK %s", irc.nick) irc.SendRawf("NICK %s", irc.nick)
} }
case <-irc.endping: case <-irc.endping:
irc.ticker.Stop() ticker.Stop()
irc.ticker2.Stop() ticker2.Stop()
irc.syncpinger <- true irc.pingerExit <- true
return return
} }
} }
} }
func (irc *Connection) Cycle() { func (irc *Connection) Loop() {
irc.SendRaw("QUIT") for !irc.stopped {
irc.Reconnect() err := <-irc.Error
if irc.stopped {
break
}
irc.log.Printf("Error: %s\n", err)
irc.Disconnect()
irc.Connect(irc.server)
}
} }
func (irc *Connection) Quit() { func (irc *Connection) Quit() {
irc.quitting = true
irc.SendRaw("QUIT") irc.SendRaw("QUIT")
irc.stopped = true
irc.Disconnect()
} }
func (irc *Connection) Join(channel string) { func (irc *Connection) Join(channel string) {
@ -149,7 +155,7 @@ func (irc *Connection) Privmsgf(target, format string, a ...interface{}) {
} }
func (irc *Connection) SendRaw(message string) { func (irc *Connection) SendRaw(message string) {
irc.pwrite <- fmt.Sprintf("%s\r\n", message) irc.pwrite <- message + "\r\n"
} }
func (irc *Connection) SendRawf(format string, a ...interface{}) { func (irc *Connection) SendRawf(format string, a ...interface{}) {
@ -165,57 +171,29 @@ func (irc *Connection) GetNick() string {
return irc.nickcurrent return irc.nickcurrent
} }
func (irc *Connection) Reconnect() error { // Sends all buffered messages (if possible),
// stops all goroutines and then closes the socket.
func (irc *Connection) Disconnect() {
close(irc.pwrite) close(irc.pwrite)
close(irc.pread) close(irc.pread)
irc.endping <- true irc.endping <- true
irc.log.Printf("Syncing Threads\n")
irc.log.Printf("Syncing Reader\n") <-irc.readerExit
<-irc.syncreader <-irc.writerExit
irc.log.Printf("Syncing Writer\n") <-irc.pingerExit
<-irc.syncwriter irc.socket.Close()
irc.log.Printf("Syncing Pinger\n") irc.socket = nil
<-irc.syncpinger
irc.log.Printf("Syncing Threads Done\n")
for {
irc.log.Printf("Reconnecting to %s\n", irc.server)
var err error
irc.Connect(irc.server)
if err == nil {
break
}
irc.log.Printf("Error: %s\n", err)
}
return nil
} }
func (irc *Connection) Loop() { func (irc *Connection) Reconnect() error {
for !irc.quitting { return irc.Connect(irc.server)
e := <-irc.Error
if irc.quitting {
break
}
irc.log.Printf("Error: %s\n", e)
irc.Reconnect()
}
close(irc.pwrite)
close(irc.pread)
irc.endping <- true
irc.log.Printf("Syncing Threads\n")
irc.log.Printf("Syncing Reader\n")
<-irc.syncreader
irc.log.Printf("Syncing Writer\n")
<-irc.syncwriter
irc.log.Printf("Syncing Pinger\n")
<-irc.syncpinger
irc.log.Printf("Syncing Threads Done\n")
} }
func (irc *Connection) Connect(server string) error { func (irc *Connection) Connect(server string) error {
irc.server = server irc.server = server
irc.stopped = false
var err error var err error
irc.log.Printf("Connecting to %s\n", irc.server)
if irc.UseTLS { if irc.UseTLS {
irc.socket, err = tls.Dial("tcp", irc.server, irc.TLSConfig) irc.socket, err = tls.Dial("tcp", irc.server, irc.TLSConfig)
} else { } else {
@ -225,17 +203,11 @@ func (irc *Connection) Connect(server string) error {
return err return err
} }
irc.log.Printf("Connected to %s (%s)\n", irc.server, irc.socket.RemoteAddr()) irc.log.Printf("Connected to %s (%s)\n", irc.server, irc.socket.RemoteAddr())
return irc.postConnect()
}
func (irc *Connection) postConnect() error { irc.pread = make(chan string, 10)
irc.pread = make(chan string, 100) irc.pwrite = make(chan string, 10)
irc.pwrite = make(chan string, 100) irc.Error = make(chan error, 2)
irc.Error = make(chan error, 10)
irc.syncreader = make(chan bool)
irc.syncwriter = make(chan bool)
irc.syncpinger = make(chan bool)
irc.endping = make(chan bool)
go irc.readLoop() go irc.readLoop()
go irc.writeLoop() go irc.writeLoop()
go irc.pingLoop() go irc.pingLoop()
@ -249,15 +221,15 @@ func (irc *Connection) postConnect() error {
} }
func IRC(nick, user string) *Connection { func IRC(nick, user string) *Connection {
irc := new(Connection) irc := &Connection{
irc.registered = false nick: nick,
irc.pread = make(chan string, 100) user: user,
irc.pwrite = make(chan string, 100) log: log.New(os.Stdout, "", log.LstdFlags),
irc.Error = make(chan error) readerExit: make(chan bool),
irc.nick = nick writerExit: make(chan bool),
irc.user = user pingerExit: make(chan bool),
irc.VerboseCallbackHandler = false endping: make(chan bool),
irc.log = log.New(os.Stdout, "", log.LstdFlags) }
irc.setupCallbacks() irc.setupCallbacks()
return irc return irc
} }

View File

@ -13,14 +13,13 @@ import (
type Connection struct { type Connection struct {
Error chan error Error chan error
Log chan string
Password string Password string
UseTLS bool UseTLS bool
TLSConfig *tls.Config TLSConfig *tls.Config
socket net.Conn socket net.Conn
pread, pwrite chan string pread, pwrite chan string
syncreader, syncwriter, syncpinger chan bool readerExit, writerExit, pingerExit chan bool
endping chan bool endping chan bool
nick string //The nickname we want. nick string //The nickname we want.
@ -30,13 +29,12 @@ type Connection struct {
server string server string
events map[string][]func(*Event) events map[string][]func(*Event)
lastMessage time.Time lastMessage time.Time
ticker, ticker2 *time.Ticker
VerboseCallbackHandler bool VerboseCallbackHandler bool
log *log.Logger log *log.Logger
quitting bool stopped bool
} }
type Event struct { type Event struct {