dispatch/pkg/irc/conn.go

205 lines
2.9 KiB
Go
Raw Normal View History

2015-06-05 22:34:13 +00:00
package irc
import (
"bufio"
"bytes"
2015-06-05 22:34:13 +00:00
"crypto/tls"
"crypto/x509"
2017-07-03 05:35:38 +00:00
"errors"
2015-06-05 22:34:13 +00:00
"fmt"
2020-05-23 07:42:20 +00:00
"net"
2015-06-05 22:34:13 +00:00
"time"
)
2017-07-03 05:35:38 +00:00
var (
ErrBadProtocol = errors.New("This server does not speak IRC")
)
2020-05-23 07:42:20 +00:00
func (c *Client) Connect() {
c.connChange(false, nil)
2015-06-05 22:34:13 +00:00
go c.run()
}
func (c *Client) Reconnect() {
c.tryConnect()
}
2015-06-05 22:34:13 +00:00
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...)
}
2016-01-15 07:26:06 +00:00
func (c *Client) run() {
c.tryConnect()
2015-06-11 02:57:52 +00:00
2016-01-15 07:26:06 +00:00
for {
select {
case <-c.quit:
c.setRegistered(false)
2016-01-15 07:26:06 +00:00
if c.Connected() {
c.disconnect()
}
2016-01-11 20:04:57 +00:00
2016-01-15 07:26:06 +00:00
c.sendRecv.Wait()
close(c.Messages)
return
2016-01-11 20:04:57 +00:00
2016-01-15 07:26:06 +00:00
case <-c.reconnect:
c.setRegistered(false)
if c.Connected() {
c.disconnect()
}
2015-06-05 22:34:13 +00:00
2016-01-15 07:26:06 +00:00
c.sendRecv.Wait()
c.reconnect = make(chan struct{})
c.state.reset()
2020-06-04 00:28:41 +00:00
c.initSASL()
2015-06-05 22:34:13 +00:00
2020-05-04 23:35:05 +00:00
time.Sleep(c.backoff.Duration())
2016-01-15 07:26:06 +00:00
c.tryConnect()
}
}
}
2015-06-05 22:34:13 +00:00
type ConnectionState struct {
Connected bool
Error error
}
func (c *Client) connChange(connected bool, err error) {
c.ConnectionChanged <- ConnectionState{
Connected: connected,
Error: err,
}
}
2016-01-15 07:26:06 +00:00
func (c *Client) disconnect() {
c.lock.Lock()
c.connected = false
c.lock.Unlock()
2015-06-05 22:34:13 +00:00
2016-01-15 07:26:06 +00:00
c.conn.Close()
2015-06-05 22:34:13 +00:00
}
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 {
c.connChange(false, err)
if _, ok := err.(x509.UnknownAuthorityError); ok {
return
}
} else {
2015-06-05 22:34:13 +00:00
return
}
2016-01-12 23:12:51 +00:00
2016-01-13 00:00:57 +00:00
time.Sleep(c.backoff.Duration())
2015-06-05 22:34:13 +00:00
}
}
2016-01-15 07:26:06 +00:00
func (c *Client) connect() error {
c.lock.Lock()
defer c.lock.Unlock()
2015-06-05 22:34:13 +00:00
2020-05-23 07:42:20 +00:00
addr := net.JoinHostPort(c.Config.Host, c.Config.Port)
if c.Config.TLS {
conn, err := tls.DialWithDialer(c.dialer, "tcp", addr, c.Config.TLSConfig)
2016-01-15 07:26:06 +00:00
if err != nil {
return err
}
2016-01-12 23:12:51 +00:00
2016-01-15 07:26:06 +00:00
c.conn = conn
} else {
2020-05-23 07:42:20 +00:00
conn, err := c.dialer.Dial("tcp", addr)
2016-01-15 07:26:06 +00:00
if err != nil {
return err
2015-06-05 22:34:13 +00:00
}
2016-01-15 07:26:06 +00:00
c.conn = conn
2015-06-05 22:34:13 +00:00
}
2016-01-15 07:26:06 +00:00
c.connected = true
c.connChange(true, nil)
c.scan = bufio.NewScanner(c.conn)
c.scan.Buffer(c.recvBuf, cap(c.recvBuf))
2016-01-15 07:26:06 +00:00
c.register()
2017-07-03 05:35:38 +00:00
c.sendRecv.Add(1)
2016-01-15 07:26:06 +00:00
go c.recv()
return nil
2015-06-05 22:34:13 +00:00
}
func (c *Client) send() {
2016-01-12 23:12:51 +00:00
defer c.sendRecv.Done()
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-12 23:12:51 +00:00
defer c.sendRecv.Done()
2015-06-05 22:34:13 +00:00
for {
if !c.scan.Scan() {
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:
c.connChange(false, nil)
close(c.reconnect)
2015-06-11 00:04:51 +00:00
return
}
2015-06-05 22:34:13 +00:00
}
b := bytes.Trim(c.scan.Bytes(), " ")
if len(b) == 0 {
continue
}
msg := ParseMessage(string(b))
2017-07-03 05:35:38 +00:00
if msg == nil {
close(c.quit)
c.connChange(false, ErrBadProtocol)
return
}
2015-06-05 22:34:13 +00:00
c.handleMessage(msg)
2020-05-23 06:05:37 +00:00
2017-04-11 04:04:59 +00:00
c.Messages <- msg
2015-06-05 22:34:13 +00:00
}
}