dispatch/irc/conn.go

206 lines
2.8 KiB
Go
Raw Normal View History

2015-06-05 22:34:13 +00:00
package irc
import (
"bufio"
"crypto/tls"
"fmt"
2016-01-14 03:28:42 +00:00
"log"
2015-06-05 22:34:13 +00:00
"net"
"strings"
"time"
)
func (c *Client) Connect(address string) {
2016-01-13 17:53:54 +00:00
c.ConnectionChanged <- false
2015-06-05 22:34:13 +00:00
if idx := strings.Index(address, ":"); idx < 0 {
c.Host = address
if c.TLS {
address += ":6697"
} else {
address += ":6667"
}
} else {
c.Host = address[:idx]
}
c.Server = address
c.dialer = &net.Dialer{Timeout: 10 * time.Second}
go c.run()
}
func (c *Client) Write(data string) {
c.out <- data + "\r\n"
}
func (c *Client) Writef(format string, a ...interface{}) {
c.out <- fmt.Sprintf(format+"\r\n", a...)
}
func (c *Client) write(data string) {
c.conn.Write([]byte(data + "\r\n"))
}
func (c *Client) writef(format string, a ...interface{}) {
fmt.Fprintf(c.conn, format+"\r\n", a...)
}
func (c *Client) connect() error {
2015-06-11 02:57:52 +00:00
c.lock.Lock()
defer c.lock.Unlock()
2015-06-05 22:34:13 +00:00
if c.TLS {
if c.TLSConfig == nil {
2016-01-11 20:04:57 +00:00
c.TLSConfig = &tls.Config{
InsecureSkipVerify: true,
}
2015-06-05 22:34:13 +00:00
}
2016-01-11 20:04:57 +00:00
conn, err := tls.DialWithDialer(c.dialer, "tcp", c.Server, c.TLSConfig)
if err != nil {
2015-06-05 22:34:13 +00:00
return err
}
2016-01-11 20:04:57 +00:00
c.conn = conn
2015-06-05 22:34:13 +00:00
} else {
2016-01-11 20:04:57 +00:00
conn, err := c.dialer.Dial("tcp", c.Server)
if err != nil {
2015-06-05 22:34:13 +00:00
return err
}
2016-01-11 20:04:57 +00:00
c.conn = conn
2015-06-05 22:34:13 +00:00
}
c.connected = true
2016-01-13 17:53:54 +00:00
c.ConnectionChanged <- true
2015-06-05 22:34:13 +00:00
c.reader = bufio.NewReader(c.conn)
2015-06-11 02:57:52 +00:00
c.register()
2015-06-05 22:34:13 +00:00
c.ready.Add(1)
go c.send()
go c.recv()
return nil
}
func (c *Client) tryConnect() {
for {
select {
case <-c.quit:
return
2016-01-12 23:12:51 +00:00
2015-06-05 22:34:13 +00:00
default:
}
err := c.connect()
if err == nil {
2016-01-13 00:00:57 +00:00
c.backoff.Reset()
2015-06-05 22:34:13 +00:00
return
}
2016-01-12 23:12:51 +00:00
2016-01-14 03:28:42 +00:00
log.Println(err)
2016-01-13 00:00:57 +00:00
time.Sleep(c.backoff.Duration())
2015-06-05 22:34:13 +00:00
}
}
func (c *Client) run() {
c.tryConnect()
2016-01-12 23:12:51 +00:00
2015-06-05 22:34:13 +00:00
for {
select {
case <-c.quit:
c.close()
return
case <-c.reconnect:
2016-01-12 23:12:51 +00:00
c.sendRecv.Wait()
2015-06-05 22:34:13 +00:00
c.reconnect = make(chan struct{})
c.once.Reset()
2016-01-12 23:12:51 +00:00
2015-06-05 22:34:13 +00:00
c.tryConnect()
}
}
}
func (c *Client) send() {
2016-01-12 23:12:51 +00:00
c.sendRecv.Add(1)
defer c.sendRecv.Done()
2015-06-05 22:34:13 +00:00
c.ready.Wait()
2016-01-12 23:12:51 +00:00
2015-06-05 22:34:13 +00:00
for {
select {
case <-c.quit:
return
case <-c.reconnect:
return
case msg := <-c.out:
_, err := c.conn.Write([]byte(msg))
if err != nil {
return
}
}
}
}
func (c *Client) recv() {
2016-01-13 18:06:55 +00:00
defer func() {
recover()
}()
2016-01-12 23:12:51 +00:00
c.sendRecv.Add(1)
defer c.sendRecv.Done()
2015-06-05 22:34:13 +00:00
for {
line, err := c.reader.ReadString('\n')
if err != nil {
2015-06-11 00:04:51 +00:00
select {
case <-c.quit:
return
2016-01-12 23:12:51 +00:00
2015-06-11 00:04:51 +00:00
default:
2016-01-13 17:53:54 +00:00
c.ConnectionChanged <- false
2016-01-12 23:12:51 +00:00
c.lock.Lock()
c.connected = false
c.lock.Unlock()
c.once.Do(c.ready.Done)
c.conn.Close()
2015-06-11 00:04:51 +00:00
close(c.reconnect)
return
}
2015-06-05 22:34:13 +00:00
}
msg := parseMessage(line)
c.Messages <- msg
switch msg.Command {
case Ping:
go c.write("PONG :" + msg.Trailing)
case ReplyWelcome:
c.once.Do(c.ready.Done)
}
}
}
func (c *Client) close() {
if c.Connected() {
2016-01-13 17:53:54 +00:00
c.ConnectionChanged <- false
2016-01-12 23:12:51 +00:00
c.lock.Lock()
c.connected = false
c.lock.Unlock()
2015-06-05 22:34:13 +00:00
c.once.Do(c.ready.Done)
2016-01-12 23:12:51 +00:00
c.conn.Close()
2015-06-05 22:34:13 +00:00
}
2016-01-12 23:12:51 +00:00
2015-06-05 22:34:13 +00:00
close(c.out)
close(c.Messages)
}