Pass config struct into irc.Client
This commit is contained in:
parent
9aac4f4e29
commit
e97c7f2ada
11 changed files with 206 additions and 181 deletions
|
@ -72,8 +72,8 @@ func (c *Client) handleCAP(msg *Message) {
|
|||
}
|
||||
|
||||
if len(c.requestedCapabilities) == 0 {
|
||||
if c.SASL != nil && c.HasCapability("sasl", c.SASL.Name()) {
|
||||
c.write("AUTHENTICATE " + c.SASL.Name())
|
||||
if c.Config.SASL != nil && c.HasCapability("sasl", c.Config.SASL.Name()) {
|
||||
c.write("AUTHENTICATE " + c.Config.SASL.Name())
|
||||
} else {
|
||||
c.write("CAP END")
|
||||
}
|
||||
|
|
|
@ -11,22 +11,27 @@ import (
|
|||
"github.com/jpillora/backoff"
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
Server string
|
||||
Host string
|
||||
TLS bool
|
||||
TLSConfig *tls.Config
|
||||
Password string
|
||||
Username string
|
||||
Realname string
|
||||
SASL SASL
|
||||
HandleNickInUse func(string) string
|
||||
|
||||
type Config struct {
|
||||
Host string
|
||||
Port string
|
||||
TLS bool
|
||||
TLSConfig *tls.Config
|
||||
Nick string
|
||||
Password string
|
||||
Username string
|
||||
Realname string
|
||||
SASL SASL
|
||||
// Version is the reply to VERSION and FINGER CTCP messages
|
||||
Version string
|
||||
// Source is the reply to SOURCE CTCP messages
|
||||
Source string
|
||||
|
||||
HandleNickInUse func(string) string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
Config Config
|
||||
|
||||
Messages chan *Message
|
||||
ConnectionChanged chan ConnectionState
|
||||
Features *Features
|
||||
|
@ -52,20 +57,35 @@ type Client struct {
|
|||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func NewClient(nick, username string) *Client {
|
||||
return &Client{
|
||||
nick: nick,
|
||||
func NewClient(config Config) *Client {
|
||||
if config.Port == "" {
|
||||
if config.TLS {
|
||||
config.Port = "6697"
|
||||
} else {
|
||||
config.Port = "6667"
|
||||
}
|
||||
}
|
||||
|
||||
if config.Username == "" {
|
||||
config.Username = config.Nick
|
||||
}
|
||||
|
||||
if config.Realname == "" {
|
||||
config.Realname = config.Nick
|
||||
}
|
||||
|
||||
c := Client{
|
||||
Config: config,
|
||||
nick: config.Nick,
|
||||
Features: NewFeatures(),
|
||||
Username: username,
|
||||
Realname: nick,
|
||||
Messages: make(chan *Message, 32),
|
||||
wantedCapabilities: clientWantedCaps,
|
||||
requestedCapabilities: map[string][]string{},
|
||||
enabledCapabilities: map[string][]string{},
|
||||
ConnectionChanged: make(chan ConnectionState, 4),
|
||||
out: make(chan string, 32),
|
||||
quit: make(chan struct{}),
|
||||
reconnect: make(chan struct{}),
|
||||
wantedCapabilities: clientWantedCaps,
|
||||
enabledCapabilities: map[string][]string{},
|
||||
requestedCapabilities: map[string][]string{},
|
||||
dialer: &net.Dialer{Timeout: 10 * time.Second},
|
||||
recvBuf: make([]byte, 0, 4096),
|
||||
backoff: &backoff.Backoff{
|
||||
|
@ -74,6 +94,12 @@ func NewClient(nick, username string) *Client {
|
|||
Jitter: true,
|
||||
},
|
||||
}
|
||||
|
||||
if config.SASL != nil {
|
||||
c.wantedCapabilities = append(c.wantedCapabilities, "sasl")
|
||||
}
|
||||
|
||||
return &c
|
||||
}
|
||||
|
||||
func (c *Client) GetNick() string {
|
||||
|
@ -113,6 +139,10 @@ func (c *Client) setRegistered(reg bool) {
|
|||
c.lock.Unlock()
|
||||
}
|
||||
|
||||
func (c *Client) Host() string {
|
||||
return c.Config.Host
|
||||
}
|
||||
|
||||
func (c *Client) Nick(nick string) {
|
||||
c.Write("NICK " + nick)
|
||||
}
|
||||
|
@ -199,16 +229,12 @@ func (c *Client) writeUser(username, realname string) {
|
|||
}
|
||||
|
||||
func (c *Client) register() {
|
||||
if c.SASL != nil {
|
||||
c.wantedCapabilities = append(c.wantedCapabilities, "sasl")
|
||||
}
|
||||
|
||||
c.writeCAP()
|
||||
if c.Password != "" {
|
||||
c.writePass(c.Password)
|
||||
if c.Config.Password != "" {
|
||||
c.writePass(c.Config.Password)
|
||||
}
|
||||
c.writeNick(c.nick)
|
||||
c.writeUser(c.Username, c.Realname)
|
||||
c.writeNick(c.Config.Nick)
|
||||
c.writeUser(c.Config.Username, c.Config.Realname)
|
||||
}
|
||||
|
||||
func (c *Client) addChannel(channel string) {
|
||||
|
|
|
@ -7,12 +7,8 @@ import (
|
|||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func testClient() *Client {
|
||||
return NewClient("test", "testing")
|
||||
}
|
||||
|
||||
func testClientSend() (*Client, chan string) {
|
||||
c := testClient()
|
||||
c := NewClient(Config{})
|
||||
conn := &mockConn{hook: make(chan string, 16)}
|
||||
c.conn = conn
|
||||
c.sendRecv.Add(1)
|
||||
|
@ -148,15 +144,16 @@ func TestAway(t *testing.T) {
|
|||
|
||||
func TestRegister(t *testing.T) {
|
||||
c, out := testClientSend()
|
||||
c.nick = "nick"
|
||||
c.Username = "user"
|
||||
c.Realname = "rn"
|
||||
c.Config.Nick = "nick"
|
||||
c.Config.Username = "user"
|
||||
c.Config.Realname = "rn"
|
||||
t.Log(c.Config)
|
||||
c.register()
|
||||
assert.Equal(t, "CAP LS 302\r\n", <-out)
|
||||
assert.Equal(t, "NICK nick\r\n", <-out)
|
||||
assert.Equal(t, "USER user 0 * :rn\r\n", <-out)
|
||||
|
||||
c.Password = "pass"
|
||||
c.Config.Password = "pass"
|
||||
c.register()
|
||||
assert.Equal(t, "CAP LS 302\r\n", <-out)
|
||||
assert.Equal(t, "PASS pass\r\n", <-out)
|
||||
|
|
|
@ -7,7 +7,7 @@ import (
|
|||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
|
@ -15,20 +15,7 @@ var (
|
|||
ErrBadProtocol = errors.New("This server does not speak IRC")
|
||||
)
|
||||
|
||||
func (c *Client) Connect(address string) {
|
||||
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
|
||||
|
||||
func (c *Client) Connect() {
|
||||
c.connChange(false, nil)
|
||||
go c.run()
|
||||
}
|
||||
|
@ -130,15 +117,16 @@ func (c *Client) connect() error {
|
|||
c.lock.Lock()
|
||||
defer c.lock.Unlock()
|
||||
|
||||
if c.TLS {
|
||||
conn, err := tls.DialWithDialer(c.dialer, "tcp", c.Server, c.TLSConfig)
|
||||
addr := net.JoinHostPort(c.Config.Host, c.Config.Port)
|
||||
if c.Config.TLS {
|
||||
conn, err := tls.DialWithDialer(c.dialer, "tcp", addr, c.Config.TLSConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c.conn = conn
|
||||
} else {
|
||||
conn, err := c.dialer.Dial("tcp", c.Server)
|
||||
conn, err := c.dialer.Dial("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -242,8 +230,8 @@ func (c *Client) recv() {
|
|||
c.Features.Parse(msg.Params)
|
||||
|
||||
case ERR_NICKNAMEINUSE, ERR_NICKCOLLISION, ERR_UNAVAILRESOURCE:
|
||||
if c.HandleNickInUse != nil {
|
||||
go c.writeNick(c.HandleNickInUse(msg.Params[1]))
|
||||
if c.Config.HandleNickInUse != nil {
|
||||
go c.writeNick(c.Config.HandleNickInUse(msg.Params[1]))
|
||||
}
|
||||
|
||||
case ERROR:
|
||||
|
|
|
@ -78,34 +78,38 @@ func (i *mockIrcd) handle(conn net.Conn) {
|
|||
}
|
||||
|
||||
func TestConnect(t *testing.T) {
|
||||
c := testClient()
|
||||
c.Connect("127.0.0.1:45678")
|
||||
assert.Equal(t, c.Host, "127.0.0.1")
|
||||
assert.Equal(t, c.Server, "127.0.0.1:45678")
|
||||
c := NewClient(Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: "45678",
|
||||
})
|
||||
c.Connect()
|
||||
waitConnAndClose(t, c)
|
||||
}
|
||||
|
||||
func TestConnectTLS(t *testing.T) {
|
||||
c := testClient()
|
||||
c.TLS = true
|
||||
c.TLSConfig = &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
}
|
||||
c.Connect("127.0.0.1:45679")
|
||||
assert.Equal(t, c.Host, "127.0.0.1")
|
||||
assert.Equal(t, c.Server, "127.0.0.1:45679")
|
||||
c := NewClient(Config{
|
||||
Host: "127.0.0.1",
|
||||
Port: "45679",
|
||||
TLS: true,
|
||||
TLSConfig: &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
},
|
||||
})
|
||||
c.Connect()
|
||||
waitConnAndClose(t, c)
|
||||
}
|
||||
|
||||
func TestConnectDefaultPorts(t *testing.T) {
|
||||
c := testClient()
|
||||
c.Connect("127.0.0.1")
|
||||
assert.Equal(t, "127.0.0.1:6667", c.Server)
|
||||
c := NewClient(Config{
|
||||
Host: "127.0.0.1",
|
||||
})
|
||||
assert.Equal(t, "6667", c.Config.Port)
|
||||
|
||||
c = testClient()
|
||||
c.TLS = true
|
||||
c.Connect("127.0.0.1")
|
||||
assert.Equal(t, "127.0.0.1:6697", c.Server)
|
||||
c = NewClient(Config{
|
||||
Host: "127.0.0.1",
|
||||
TLS: true,
|
||||
})
|
||||
assert.Equal(t, "6697", c.Config.Port)
|
||||
}
|
||||
|
||||
func TestWrite(t *testing.T) {
|
||||
|
@ -121,7 +125,7 @@ func TestWrite(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRecv(t *testing.T) {
|
||||
c := testClient()
|
||||
c := NewClient(Config{})
|
||||
conn := &mockConn{hook: make(chan string, 16)}
|
||||
c.conn = conn
|
||||
|
||||
|
@ -141,7 +145,7 @@ func TestRecv(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestRecvTriggersReconnect(t *testing.T) {
|
||||
c := testClient()
|
||||
c := NewClient(Config{})
|
||||
c.conn = &mockConn{}
|
||||
c.scan = bufio.NewScanner(bytes.NewBufferString("001 bob\r\n"))
|
||||
done := make(chan struct{})
|
||||
|
@ -164,7 +168,7 @@ func TestRecvTriggersReconnect(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestClose(t *testing.T) {
|
||||
c := testClient()
|
||||
c := NewClient(Config{})
|
||||
close(c.quit)
|
||||
ok := false
|
||||
done := make(chan struct{})
|
||||
|
|
|
@ -48,22 +48,22 @@ func (c *Client) handleCTCP(ctcp *CTCP, msg *Message) {
|
|||
c.ReplyCTCP(msg.Nick, ctcp.Command, ClientInfo)
|
||||
|
||||
case "FINGER", "VERSION":
|
||||
if c.Version != "" {
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, c.Version)
|
||||
if c.Config.Version != "" {
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, c.Config.Version)
|
||||
}
|
||||
|
||||
case "PING":
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, ctcp.Params)
|
||||
|
||||
case "SOURCE":
|
||||
if c.Source != "" {
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, c.Source)
|
||||
if c.Config.Source != "" {
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, c.Config.Source)
|
||||
}
|
||||
|
||||
case "TIME":
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, time.Now().UTC().Format(time.RFC3339))
|
||||
|
||||
case "USERINFO":
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, fmt.Sprintf("%s (%s)", c.GetNick(), c.Realname))
|
||||
c.ReplyCTCP(msg.Nick, ctcp.Command, fmt.Sprintf("%s (%s)", c.GetNick(), c.Config.Realname))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ func (s *SASLExternal) Encode() string {
|
|||
func (c *Client) handleSASL(msg *Message) {
|
||||
switch msg.Command {
|
||||
case AUTHENTICATE:
|
||||
auth := c.SASL.Encode()
|
||||
auth := c.Config.SASL.Encode()
|
||||
|
||||
for len(auth) >= 400 {
|
||||
c.write("AUTHENTICATE " + auth)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue