Added configurable timeouts and overridable version string

This commit is contained in:
Andrew Montgomery-Hurrell 2014-02-09 10:20:58 +00:00
parent a1d207d5fa
commit c0e6d50e0c
3 changed files with 47 additions and 9 deletions

49
irc.go
View File

@ -23,7 +23,21 @@ func (irc *Connection) readLoop() {
br := bufio.NewReaderSize(irc.socket, 512) br := bufio.NewReaderSize(irc.socket, 512)
for { for {
// Set a read deadline based on the combined timeout and ping frequency
// We should ALWAYS have received a response from the server within the timeout
// after our own pings
if irc.socket != nil {
irc.socket.SetReadDeadline(time.Now().Add(irc.Timeout + irc.PingFreq))
}
msg, err := br.ReadString('\n') msg, err := br.ReadString('\n')
// We got past our blocking read, so bin timeout
if irc.socket != nil {
var zero time.Time
irc.socket.SetReadDeadline(zero)
}
if err != nil { if err != nil {
irc.Error <- err irc.Error <- err
break break
@ -77,7 +91,16 @@ func (irc *Connection) writeLoop() {
if irc.Debug { if irc.Debug {
irc.log.Printf("--> %s\n", b) irc.log.Printf("--> %s\n", b)
} }
// Set a write deadline based on the time out
irc.socket.SetWriteDeadline(time.Now().Add(irc.Timeout))
_, err := irc.socket.Write([]byte(b)) _, err := irc.socket.Write([]byte(b))
// Past blocking write, bin timeout
var zero time.Time
irc.socket.SetWriteDeadline(zero)
if err != nil { if err != nil {
irc.Error <- err irc.Error <- err
break break
@ -86,19 +109,19 @@ func (irc *Connection) writeLoop() {
irc.writerExit <- true irc.writerExit <- true
} }
//Pings the server if we have not recived any messages for 5 minutes //Pings the server if we have not received any messages for 5 minutes
func (irc *Connection) pingLoop() { func (irc *Connection) pingLoop() {
ticker := time.NewTicker(1 * time.Minute) //Tick every minute. ticker := time.NewTicker(1 * time.Minute) // Tick every minute for monitoring
ticker2 := time.NewTicker(15 * time.Minute) //Tick every 15 minutes. ticker2 := time.NewTicker(irc.PingFreq) // Tick at the ping frequency.
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
//Ping if we haven't received anything from the server within 4 minutes //Ping if we haven't received anything from the server within the keep alive period
if time.Since(irc.lastMessage) >= (4 * time.Minute) { if time.Since(irc.lastMessage) >= irc.KeepAlive {
irc.SendRawf("PING %d", time.Now().UnixNano()) irc.SendRawf("PING %d", time.Now().UnixNano())
} }
case <-ticker2.C: case <-ticker2.C:
//Ping every 15 minutes. //Ping at the ping frequency
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.
if irc.nick != irc.nickcurrent { if irc.nick != irc.nickcurrent {
@ -192,6 +215,10 @@ func (irc *Connection) Disconnect() {
<-irc.pingerExit <-irc.pingerExit
irc.socket.Close() irc.socket.Close()
irc.socket = nil irc.socket = nil
if irc.netsock != nil {
irc.netsock.Close()
irc.netsock = nil
}
} }
func (irc *Connection) Reconnect() error { func (irc *Connection) Reconnect() error {
@ -204,9 +231,11 @@ func (irc *Connection) Connect(server string) error {
var err error var err error
if irc.UseTLS { if irc.UseTLS {
irc.socket, err = tls.Dial("tcp", irc.server, irc.TLSConfig) if irc.netsock, err = net.DialTimeout("tcp", irc.server, irc.Timeout); err == nil {
irc.socket = tls.Client(irc.netsock, irc.TLSConfig)
}
} else { } else {
irc.socket, err = net.Dial("tcp", irc.server) irc.socket, err = net.DialTimeout("tcp", irc.server, irc.Timeout)
} }
if err != nil { if err != nil {
return err return err
@ -238,6 +267,10 @@ func IRC(nick, user string) *Connection {
writerExit: make(chan bool), writerExit: make(chan bool),
pingerExit: make(chan bool), pingerExit: make(chan bool),
endping: make(chan bool), endping: 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

View File

@ -84,7 +84,7 @@ func (irc *Connection) setupCallbacks() {
//Version handler //Version handler
irc.AddCallback("CTCP_VERSION", func(e *Event) { irc.AddCallback("CTCP_VERSION", func(e *Event) {
irc.SendRawf("NOTICE %s :\x01VERSION %s\x01", e.Nick, VERSION) irc.SendRawf("NOTICE %s :\x01VERSION %s\x01", e.Nick, irc.Version)
}) })
irc.AddCallback("CTCP_USERINFO", func(e *Event) { irc.AddCallback("CTCP_USERINFO", func(e *Event) {

View File

@ -17,8 +17,13 @@ type Connection struct {
Password string Password string
UseTLS bool UseTLS bool
TLSConfig *tls.Config TLSConfig *tls.Config
Version string
Timeout time.Duration
PingFreq time.Duration
KeepAlive time.Duration
socket net.Conn socket net.Conn
netsock net.Conn
pread, pwrite chan string pread, pwrite chan string
readerExit, writerExit, pingerExit chan bool readerExit, writerExit, pingerExit chan bool
endping chan bool endping chan bool