Close channel to signal goroutines to quit and waitgroup to confirm that they have

This commit is contained in:
alsm 2014-05-02 23:20:51 +01:00
parent 50d8ba24ee
commit f27b0b53e2
2 changed files with 28 additions and 40 deletions

51
irc.go
View File

@ -37,12 +37,12 @@ const (
// Read data from a connection. To be used as a goroutine.
func (irc *Connection) readLoop() {
defer irc.Done()
br := bufio.NewReaderSize(irc.socket, 512)
for {
select {
case <-irc.endread:
irc.readerExit <- true
case <-irc.end:
return
default:
// Set a read deadline based on the combined timeout and ping frequency
@ -97,21 +97,19 @@ func (irc *Connection) readLoop() {
irc.RunCallbacks(event)
}
}
irc.readerExit <- true
return
}
// Loop to write to a connection. To be used as a goroutine.
func (irc *Connection) writeLoop() {
defer irc.Done()
for {
select {
case <-irc.endwrite:
irc.writerExit <- true
case <-irc.end:
return
default:
b, ok := <-irc.pwrite
if !ok || b == "" || irc.socket == nil {
irc.writerExit <- true
return
}
@ -130,17 +128,17 @@ func (irc *Connection) writeLoop() {
if err != nil {
irc.Error <- err
irc.writerExit <- true
return
}
}
}
irc.writerExit <- true
return
}
// 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() {
defer irc.Done()
ticker := time.NewTicker(1 * time.Minute) // Tick every minute for monitoring
ticker2 := time.NewTicker(irc.PingFreq) // Tick at the ping frequency.
for {
@ -158,10 +156,9 @@ func (irc *Connection) pingLoop() {
irc.nickcurrent = irc.nick
irc.SendRawf("NICK %s", irc.nick)
}
case <-irc.endping:
case <-irc.end:
ticker.Stop()
ticker2.Stop()
irc.pingerExit <- true
return
}
}
@ -222,7 +219,7 @@ func (irc *Connection) Noticef(target, format string, a ...interface{}) {
// Send (action) message to a target (channel or nickname).
// No clear RFC on this one...
func (irc *Connection) Action(target, message string) {
irc.pwrite <- fmt.Sprintf("PRIVMSG %s :\001ACTION %s\001\r\n", target, message)
irc.pwrite <- fmt.Sprintf("PRIVMSG %s :\001ACTION %s\001\r\n", target, message)
}
// Send (private) message to a target (channel or nickname).
@ -284,15 +281,11 @@ func (irc *Connection) Mode(target string, modestring ...string) {
// A disconnect sends all buffered messages (if possible),
// stops all goroutines and then closes the socket.
func (irc *Connection) Disconnect() {
irc.endping <- true
irc.endwrite <- true
irc.endread <- true
close(irc.end)
close(irc.pwrite)
close(irc.pread)
<-irc.readerExit
<-irc.writerExit
<-irc.pingerExit
irc.Wait()
irc.socket.Close()
irc.socket = nil
if irc.netsock != nil {
@ -362,6 +355,7 @@ func (irc *Connection) Connect(server string) error {
irc.pwrite = make(chan string, 10)
irc.Error = make(chan error, 2)
irc.Add(3)
go irc.readLoop()
go irc.writeLoop()
go irc.pingLoop()
@ -387,19 +381,14 @@ func IRC(nick, user string) *Connection {
}
irc := &Connection{
nick: nick,
user: user,
Log: log.New(os.Stdout, "", log.LstdFlags),
readerExit: make(chan bool),
writerExit: make(chan bool),
pingerExit: make(chan bool),
endping: make(chan bool),
endread: make(chan bool),
endwrite: make(chan bool),
Version: VERSION,
KeepAlive: 4 * time.Minute,
Timeout: 1 * time.Minute,
PingFreq: 15 * time.Minute,
nick: nick,
user: user,
Log: log.New(os.Stdout, "", log.LstdFlags),
end: make(chan struct{}),
Version: VERSION,
KeepAlive: 4 * time.Minute,
Timeout: 1 * time.Minute,
PingFreq: 15 * time.Minute,
}
irc.setupCallbacks()
return irc

View File

@ -8,10 +8,12 @@ import (
"crypto/tls"
"log"
"net"
"sync"
"time"
)
type Connection struct {
sync.WaitGroup
Debug bool
Error chan error
Password string
@ -22,11 +24,10 @@ type Connection struct {
PingFreq time.Duration
KeepAlive time.Duration
socket net.Conn
netsock net.Conn
pread, pwrite chan string
readerExit, writerExit, pingerExit chan bool
endping, endread, endwrite chan bool
socket net.Conn
netsock net.Conn
pread, pwrite chan string
end chan struct{}
nick string //The nickname we want.
nickcurrent string //The nickname we currently have.
@ -43,7 +44,6 @@ type Connection struct {
stopped bool
}
// A struct to represent an event.
type Event struct {
Code string
@ -55,9 +55,8 @@ type Event struct {
Arguments []string
}
// Retrieve the last message from Event arguments.
// This function leaves the arguments untouched and
// Retrieve the last message from Event arguments.
// This function leaves the arguments untouched and
// returns an empty string if there are none.
func (e *Event) Message() string {
if len(e.Arguments) == 0 {