Merge pull request #29 from alsm/master
Close channel to signal goroutines to quit and waitgroup to confirm that...
This commit is contained in:
commit
2e87f54e96
51
irc.go
51
irc.go
@ -37,12 +37,12 @@ const (
|
|||||||
|
|
||||||
// Read data from a connection. To be used as a goroutine.
|
// Read data from a connection. To be used as a goroutine.
|
||||||
func (irc *Connection) readLoop() {
|
func (irc *Connection) readLoop() {
|
||||||
|
defer irc.Done()
|
||||||
br := bufio.NewReaderSize(irc.socket, 512)
|
br := bufio.NewReaderSize(irc.socket, 512)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-irc.endread:
|
case <-irc.end:
|
||||||
irc.readerExit <- true
|
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
// Set a read deadline based on the combined timeout and ping frequency
|
// Set a read deadline based on the combined timeout and ping frequency
|
||||||
@ -97,21 +97,19 @@ func (irc *Connection) readLoop() {
|
|||||||
irc.RunCallbacks(event)
|
irc.RunCallbacks(event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
irc.readerExit <- true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loop to write to a connection. To be used as a goroutine.
|
// Loop to write to a connection. To be used as a goroutine.
|
||||||
func (irc *Connection) writeLoop() {
|
func (irc *Connection) writeLoop() {
|
||||||
|
defer irc.Done()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-irc.endwrite:
|
case <-irc.end:
|
||||||
irc.writerExit <- true
|
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
b, ok := <-irc.pwrite
|
b, ok := <-irc.pwrite
|
||||||
if !ok || b == "" || irc.socket == nil {
|
if !ok || b == "" || irc.socket == nil {
|
||||||
irc.writerExit <- true
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,17 +128,17 @@ func (irc *Connection) writeLoop() {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
irc.Error <- err
|
irc.Error <- err
|
||||||
irc.writerExit <- true
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
irc.writerExit <- true
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
// to keep the connection alive. To be used as a goroutine.
|
||||||
func (irc *Connection) pingLoop() {
|
func (irc *Connection) pingLoop() {
|
||||||
|
defer irc.Done()
|
||||||
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.
|
||||||
for {
|
for {
|
||||||
@ -158,10 +156,9 @@ func (irc *Connection) pingLoop() {
|
|||||||
irc.nickcurrent = irc.nick
|
irc.nickcurrent = irc.nick
|
||||||
irc.SendRawf("NICK %s", irc.nick)
|
irc.SendRawf("NICK %s", irc.nick)
|
||||||
}
|
}
|
||||||
case <-irc.endping:
|
case <-irc.end:
|
||||||
ticker.Stop()
|
ticker.Stop()
|
||||||
ticker2.Stop()
|
ticker2.Stop()
|
||||||
irc.pingerExit <- true
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -222,7 +219,7 @@ func (irc *Connection) Noticef(target, format string, a ...interface{}) {
|
|||||||
// Send (action) message to a target (channel or nickname).
|
// Send (action) message to a target (channel or nickname).
|
||||||
// No clear RFC on this one...
|
// No clear RFC on this one...
|
||||||
func (irc *Connection) Action(target, message string) {
|
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).
|
// 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),
|
// 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
|
close(irc.end)
|
||||||
irc.endwrite <- true
|
|
||||||
irc.endread <- true
|
|
||||||
close(irc.pwrite)
|
close(irc.pwrite)
|
||||||
close(irc.pread)
|
close(irc.pread)
|
||||||
|
|
||||||
<-irc.readerExit
|
irc.Wait()
|
||||||
<-irc.writerExit
|
|
||||||
<-irc.pingerExit
|
|
||||||
irc.socket.Close()
|
irc.socket.Close()
|
||||||
irc.socket = nil
|
irc.socket = nil
|
||||||
if irc.netsock != nil {
|
if irc.netsock != nil {
|
||||||
@ -362,6 +355,7 @@ func (irc *Connection) Connect(server string) error {
|
|||||||
irc.pwrite = make(chan string, 10)
|
irc.pwrite = make(chan string, 10)
|
||||||
irc.Error = make(chan error, 2)
|
irc.Error = make(chan error, 2)
|
||||||
|
|
||||||
|
irc.Add(3)
|
||||||
go irc.readLoop()
|
go irc.readLoop()
|
||||||
go irc.writeLoop()
|
go irc.writeLoop()
|
||||||
go irc.pingLoop()
|
go irc.pingLoop()
|
||||||
@ -387,19 +381,14 @@ func IRC(nick, user string) *Connection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
irc := &Connection{
|
irc := &Connection{
|
||||||
nick: nick,
|
nick: nick,
|
||||||
user: user,
|
user: user,
|
||||||
Log: log.New(os.Stdout, "", log.LstdFlags),
|
Log: log.New(os.Stdout, "", log.LstdFlags),
|
||||||
readerExit: make(chan bool),
|
end: make(chan struct{}),
|
||||||
writerExit: make(chan bool),
|
Version: VERSION,
|
||||||
pingerExit: make(chan bool),
|
KeepAlive: 4 * time.Minute,
|
||||||
endping: make(chan bool),
|
Timeout: 1 * time.Minute,
|
||||||
endread: make(chan bool),
|
PingFreq: 15 * time.Minute,
|
||||||
endwrite: make(chan bool),
|
|
||||||
Version: VERSION,
|
|
||||||
KeepAlive: 4 * time.Minute,
|
|
||||||
Timeout: 1 * time.Minute,
|
|
||||||
PingFreq: 15 * time.Minute,
|
|
||||||
}
|
}
|
||||||
irc.setupCallbacks()
|
irc.setupCallbacks()
|
||||||
return irc
|
return irc
|
||||||
|
@ -8,10 +8,12 @@ import (
|
|||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"log"
|
"log"
|
||||||
"net"
|
"net"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Connection struct {
|
type Connection struct {
|
||||||
|
sync.WaitGroup
|
||||||
Debug bool
|
Debug bool
|
||||||
Error chan error
|
Error chan error
|
||||||
Password string
|
Password string
|
||||||
@ -22,11 +24,10 @@ type Connection struct {
|
|||||||
PingFreq time.Duration
|
PingFreq time.Duration
|
||||||
KeepAlive time.Duration
|
KeepAlive time.Duration
|
||||||
|
|
||||||
socket net.Conn
|
socket net.Conn
|
||||||
netsock net.Conn
|
netsock net.Conn
|
||||||
pread, pwrite chan string
|
pread, pwrite chan string
|
||||||
readerExit, writerExit, pingerExit chan bool
|
end chan struct{}
|
||||||
endping, endread, endwrite chan bool
|
|
||||||
|
|
||||||
nick string //The nickname we want.
|
nick string //The nickname we want.
|
||||||
nickcurrent string //The nickname we currently have.
|
nickcurrent string //The nickname we currently have.
|
||||||
@ -43,7 +44,6 @@ type Connection struct {
|
|||||||
stopped bool
|
stopped bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// A struct to represent an event.
|
// A struct to represent an event.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
Code string
|
Code string
|
||||||
@ -55,7 +55,6 @@ type Event struct {
|
|||||||
Arguments []string
|
Arguments []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Retrieve the last message from Event arguments.
|
// Retrieve the last message from Event arguments.
|
||||||
// This function leaves the arguments untouched and
|
// This function leaves the arguments untouched and
|
||||||
// returns an empty string if there are none.
|
// returns an empty string if there are none.
|
||||||
|
Loading…
Reference in New Issue
Block a user