mirror of https://github.com/fluffle/goirc
Merge branch 'release'
Conflicts: client/connection.go client/connection_test.go
This commit is contained in:
commit
9c67c42fa1
|
@ -5,14 +5,9 @@ GoIRC Client Framework
|
|||
|
||||
Pretty simple, really:
|
||||
|
||||
goinstall github.com/fluffle/goirc
|
||||
go get github.com/fluffle/goirc/client
|
||||
|
||||
You can build the test client also with:
|
||||
|
||||
make
|
||||
./gobot
|
||||
|
||||
This will connect to freenode and join `#go-nuts` by default, so be careful ;-)
|
||||
There is some example code that demonstrates usage of the library in `client.go`. This will connect to freenode and join `#go-nuts` by default, so be careful ;-)
|
||||
|
||||
### Using the framework
|
||||
|
||||
|
|
|
@ -3,20 +3,16 @@ package client
|
|||
import (
|
||||
"bufio"
|
||||
"crypto/tls"
|
||||
"github.com/fluffle/goevent/event"
|
||||
"github.com/fluffle/golog/logging"
|
||||
"github.com/fluffle/goirc/state"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/fluffle/goevent/event"
|
||||
"github.com/fluffle/goirc/state"
|
||||
"github.com/fluffle/golog/logging"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
second = int64(1e9)
|
||||
)
|
||||
|
||||
// An IRC connection is represented by this struct.
|
||||
type Conn struct {
|
||||
// Connection Hostname and Nickname
|
||||
|
@ -57,14 +53,12 @@ type Conn struct {
|
|||
// Client->server ping frequency, in seconds. Defaults to 3m.
|
||||
PingFreq int64
|
||||
|
||||
// Socket timeout, in seconds. Default to 5m.
|
||||
Timeout int64
|
||||
|
||||
// Set this to true to disable flood protection and false to re-enable
|
||||
Flood bool
|
||||
|
||||
// Internal counters for flood protection
|
||||
badness, lastsent int64
|
||||
badness time.Duration
|
||||
lastsent time.Time
|
||||
}
|
||||
|
||||
// Creates a new IRC connection object, but doesn't connect to anything so
|
||||
|
@ -90,22 +84,21 @@ func Client(nick, ident, name string,
|
|||
return nil
|
||||
}
|
||||
conn := &Conn{
|
||||
ER: r,
|
||||
ED: r,
|
||||
l: l,
|
||||
st: false,
|
||||
in: make(chan *Line, 32),
|
||||
out: make(chan string, 32),
|
||||
cSend: make(chan bool),
|
||||
cLoop: make(chan bool),
|
||||
cPing: make(chan bool),
|
||||
SSL: false,
|
||||
SSLConfig: nil,
|
||||
PingFreq: 180,
|
||||
Timeout: 300,
|
||||
Flood: false,
|
||||
badness: 0,
|
||||
lastsent: 0,
|
||||
ER: r,
|
||||
ED: r,
|
||||
l: l,
|
||||
st: false,
|
||||
in: make(chan *Line, 32),
|
||||
out: make(chan string, 32),
|
||||
cSend: make(chan bool),
|
||||
cLoop: make(chan bool),
|
||||
cPing: make(chan bool),
|
||||
SSL: false,
|
||||
SSLConfig: nil,
|
||||
PingFreq: 180,
|
||||
Flood: false,
|
||||
badness: 0,
|
||||
lastsent: time.Now(),
|
||||
}
|
||||
conn.addIntHandlers()
|
||||
conn.Me = state.NewNick(nick, l)
|
||||
|
@ -151,9 +144,9 @@ func (conn *Conn) initialise() {
|
|||
// on the connection to the IRC server, set Conn.SSL to true before calling
|
||||
// Connect(). The port will default to 6697 if ssl is enabled, and 6667
|
||||
// otherwise. You can also provide an optional connect password.
|
||||
func (conn *Conn) Connect(host string, pass ...string) os.Error {
|
||||
func (conn *Conn) Connect(host string, pass ...string) error {
|
||||
if conn.Connected {
|
||||
return os.NewError(fmt.Sprintf(
|
||||
return errors.New(fmt.Sprintf(
|
||||
"irc.Connect(): already connected to %s, cannot connect to %s",
|
||||
conn.Host, host))
|
||||
}
|
||||
|
@ -196,7 +189,6 @@ func (conn *Conn) postConnect() {
|
|||
conn.io = bufio.NewReadWriter(
|
||||
bufio.NewReader(conn.sock),
|
||||
bufio.NewWriter(conn.sock))
|
||||
conn.sock.SetTimeout(conn.Timeout * second)
|
||||
go conn.send()
|
||||
go conn.recv()
|
||||
if conn.PingFreq > 0 {
|
||||
|
@ -231,7 +223,7 @@ func (conn *Conn) recv() {
|
|||
for {
|
||||
s, err := conn.io.ReadString('\n')
|
||||
if err != nil {
|
||||
conn.l.Error("irc.recv(): %s", err.String())
|
||||
conn.l.Error("irc.recv(): %s", err.Error())
|
||||
conn.shutdown()
|
||||
return
|
||||
}
|
||||
|
@ -239,7 +231,7 @@ func (conn *Conn) recv() {
|
|||
conn.l.Debug("<- %s", s)
|
||||
|
||||
if line := parseLine(s); line != nil {
|
||||
line.Time = time.LocalTime()
|
||||
line.Time = time.Now()
|
||||
conn.in <- line
|
||||
} else {
|
||||
conn.l.Warn("irc.recv(): problems parsing line:\n %s", s)
|
||||
|
@ -278,21 +270,21 @@ func (conn *Conn) runLoop() {
|
|||
// using Hybrid's algorithm to rate limit if conn.Flood is false.
|
||||
func (conn *Conn) write(line string) {
|
||||
if !conn.Flood {
|
||||
if t := conn.rateLimit(int64(len(line))); t != 0 {
|
||||
if t := conn.rateLimit(len(line)); t != 0 {
|
||||
// sleep for the current line's time value before sending it
|
||||
conn.l.Debug("irc.rateLimit(): Flood! Sleeping for %.2f secs.",
|
||||
float64(t)/float64(second))
|
||||
t.Seconds())
|
||||
<-time.After(t)
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := conn.io.WriteString(line + "\r\n"); err != nil {
|
||||
conn.l.Error("irc.send(): %s", err.String())
|
||||
conn.l.Error("irc.send(): %s", err.Error())
|
||||
conn.shutdown()
|
||||
return
|
||||
}
|
||||
if err := conn.io.Flush(); err != nil {
|
||||
conn.l.Error("irc.send(): %s", err.String())
|
||||
conn.l.Error("irc.send(): %s", err.Error())
|
||||
conn.shutdown()
|
||||
return
|
||||
}
|
||||
|
@ -300,19 +292,19 @@ func (conn *Conn) write(line string) {
|
|||
}
|
||||
|
||||
// Implement Hybrid's flood control algorithm to rate-limit outgoing lines.
|
||||
func (conn *Conn) rateLimit(chars int64) int64 {
|
||||
func (conn *Conn) rateLimit(chars int) time.Duration {
|
||||
// Hybrid's algorithm allows for 2 seconds per line and an additional
|
||||
// 1/120 of a second per character on that line.
|
||||
linetime := 2*second + chars*second/120
|
||||
elapsed := time.Nanoseconds() - conn.lastsent
|
||||
linetime := 2*time.Second + time.Duration(chars)*time.Second/120
|
||||
elapsed := time.Now().Sub(conn.lastsent)
|
||||
if conn.badness += linetime - elapsed; conn.badness < 0 {
|
||||
// negative badness times are badness...
|
||||
conn.badness = int64(0)
|
||||
conn.badness = 0
|
||||
}
|
||||
conn.lastsent = time.Nanoseconds()
|
||||
conn.lastsent = time.Now()
|
||||
// If we've sent more than 10 second's worth of lines according to the
|
||||
// calculation above, then we're at risk of "Excess Flood".
|
||||
if conn.badness > 10*second {
|
||||
if conn.badness > 10*time.Second {
|
||||
return linetime
|
||||
}
|
||||
return 0
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"github.com/fluffle/goevent/event"
|
||||
"github.com/fluffle/golog/logging"
|
||||
"github.com/fluffle/goirc/state"
|
||||
"gomock.googlecode.com/hg/gomock"
|
||||
gomock "github.com/dsymonds/gomock/gomock"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
@ -92,8 +92,12 @@ func TestClientAndStateTracking(t *testing.T) {
|
|||
l := logging.NewMockLogger(ctrl)
|
||||
st := state.NewMockStateTracker(ctrl)
|
||||
|
||||
for n, h := range intHandlers {
|
||||
r.EXPECT().AddHandler(h, n)
|
||||
for n, _ := range intHandlers {
|
||||
// We can't use EXPECT() here as comparisons of functions are
|
||||
// no longer valid in Go, which causes reflect.DeepEqual to bail.
|
||||
// Instead, ignore the function arg and just ensure that all the
|
||||
// handler names are correctly passed to AddHandler.
|
||||
ctrl.RecordCall(r, "AddHandler", gomock.Any(), []string{n})
|
||||
}
|
||||
c := Client("test", "test", "Testing IRC", r, l)
|
||||
|
||||
|
@ -110,8 +114,9 @@ func TestClientAndStateTracking(t *testing.T) {
|
|||
}
|
||||
|
||||
// OK, while we're here with a mock event registry...
|
||||
for n, h := range stHandlers {
|
||||
r.EXPECT().AddHandler(h, n)
|
||||
for n, _ := range stHandlers {
|
||||
// See above.
|
||||
ctrl.RecordCall(r, "AddHandler", gomock.Any(), []string{n})
|
||||
}
|
||||
c.EnableStateTracking()
|
||||
|
||||
|
@ -128,8 +133,9 @@ func TestClientAndStateTracking(t *testing.T) {
|
|||
me := c.Me
|
||||
c.ST = st
|
||||
st.EXPECT().Wipe()
|
||||
for n, h := range stHandlers {
|
||||
r.EXPECT().DelHandler(h, n)
|
||||
for n, _ := range stHandlers {
|
||||
// See above.
|
||||
ctrl.RecordCall(r, "DelHandler", gomock.Any(), []string{n})
|
||||
}
|
||||
c.DisableStateTracking()
|
||||
if c.st || c.ST != nil || c.Me != me {
|
||||
|
@ -412,8 +418,8 @@ func TestWrite(t *testing.T) {
|
|||
s.nc.Expect("yo momma")
|
||||
|
||||
// Flood control is disabled -- setUp sets c.Flood = true -- so we should
|
||||
// not have set c.badness or c.lastsent at this point.
|
||||
if c.badness != 0 || c.lastsent != 0 {
|
||||
// not have set c.badness at this point.
|
||||
if c.badness != 0 {
|
||||
t.Errorf("Flood control used when Flood = true.")
|
||||
}
|
||||
|
||||
|
@ -421,8 +427,8 @@ func TestWrite(t *testing.T) {
|
|||
c.write("she so useless")
|
||||
s.nc.Expect("she so useless")
|
||||
|
||||
// The lastsent time should have been updated now.
|
||||
if c.lastsent == 0 {
|
||||
// The lastsent time should have been updated very recently...
|
||||
if time.Now().Sub(c.lastsent) > time.Millisecond {
|
||||
t.Errorf("Flood control not used when Flood = false.")
|
||||
}
|
||||
|
||||
|
@ -449,24 +455,40 @@ func TestRateLimit(t *testing.T) {
|
|||
c, s := setUp(t)
|
||||
defer s.tearDown()
|
||||
|
||||
if c.badness != 0 || c.lastsent != 0 {
|
||||
if c.badness != 0 {
|
||||
t.Errorf("Bad initial values for rate limit variables.")
|
||||
}
|
||||
|
||||
// badness will still be 0 because lastsent was 0 before rateLimit.
|
||||
if l := c.rateLimit(60); l != 0 || c.badness != 0 || c.lastsent == 0 {
|
||||
t.Errorf("Rate limit variables not updated correctly after rateLimit.")
|
||||
// We'll be needing this later...
|
||||
abs := func(i time.Duration) time.Duration {
|
||||
if (i < 0) {
|
||||
return -i
|
||||
}
|
||||
return i
|
||||
}
|
||||
|
||||
// Since the changes to the time module, c.lastsent is now a time.Time.
|
||||
// It's initialised on client creation to time.Now() which for the purposes
|
||||
// of this test was probably around 1.2 ms ago. This is inconvenient.
|
||||
// Making it >10s ago effectively clears out the inconsistency, as this
|
||||
// makes elapsed > linetime and thus zeros c.badness and resets c.lastsent.
|
||||
c.lastsent = time.Now().Add(-10 * time.Second)
|
||||
if l := c.rateLimit(60); l != 0 || c.badness != 0 {
|
||||
t.Errorf("Rate limit got non-zero badness from long-ago lastsent.")
|
||||
}
|
||||
|
||||
// So, time at the nanosecond resolution is a bit of a bitch. Choosing 60
|
||||
// characters as the line length means we should be increasing badness by
|
||||
// 2.5 seconds minus the delta between the two ratelimit calls. This should
|
||||
// be minimal but it's guaranteed that it won't be zero. Use 1us as a fuzz.
|
||||
// This seems to be the minimum timer resolution, on my laptop at least...
|
||||
if l := c.rateLimit(60); l != 0 || c.badness - int64(25*1e8) > 1e3 {
|
||||
// be minimal but it's guaranteed that it won't be zero. Use 10us as a fuzz.
|
||||
if l := c.rateLimit(60); l != 0 || abs(c.badness - 25*1e8) > 10 * time.Microsecond {
|
||||
t.Errorf("Rate limit calculating badness incorrectly.")
|
||||
}
|
||||
// At this point, we can tip over the badness scale, with a bit of help.
|
||||
if l := c.rateLimit(360); l == 80*1e8 || c.badness - int64(105*1e8) > 1e3 {
|
||||
// 720 chars => +8 seconds of badness => 10.5 seconds => ratelimit
|
||||
if l := c.rateLimit(720); l != 8 * time.Second ||
|
||||
abs(c.badness - 105*1e8) > 10 * time.Microsecond {
|
||||
t.Errorf("Rate limit failed to return correct limiting values.")
|
||||
t.Errorf("l=%d, badness=%d", l, c.badness)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package client
|
|||
|
||||
import (
|
||||
"github.com/fluffle/goirc/state"
|
||||
"gomock.googlecode.com/hg/gomock"
|
||||
gomock "github.com/dsymonds/gomock/gomock"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ type Line struct {
|
|||
Nick, Ident, Host, Src string
|
||||
Cmd, Raw string
|
||||
Args []string
|
||||
Time *time.Time
|
||||
Time time.Time
|
||||
}
|
||||
|
||||
// NOTE: this doesn't copy l.Time (this should be read-only anyway)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
|
@ -23,7 +24,7 @@ type mockNetConn struct {
|
|||
rc chan bool
|
||||
|
||||
closed bool
|
||||
rt, wt int64
|
||||
rt, wt time.Time
|
||||
}
|
||||
|
||||
func MockNetConn(t *testing.T) *mockNetConn {
|
||||
|
@ -96,9 +97,9 @@ func (m *mockNetConn) ExpectNothing() {
|
|||
}
|
||||
|
||||
// Implement net.Conn interface
|
||||
func (m *mockNetConn) Read(b []byte) (int, os.Error) {
|
||||
func (m *mockNetConn) Read(b []byte) (int, error) {
|
||||
if m.closed {
|
||||
return 0, os.EINVAL
|
||||
return 0, os.ErrInvalid
|
||||
}
|
||||
l := 0
|
||||
select {
|
||||
|
@ -106,14 +107,14 @@ func (m *mockNetConn) Read(b []byte) (int, os.Error) {
|
|||
l = len(s)
|
||||
copy(b, s)
|
||||
case <-m.closers[mockReadCloser]:
|
||||
return 0, os.EOF
|
||||
return 0, io.EOF
|
||||
}
|
||||
return l, nil
|
||||
}
|
||||
|
||||
func (m *mockNetConn) Write(s []byte) (int, os.Error) {
|
||||
func (m *mockNetConn) Write(s []byte) (int, error) {
|
||||
if m.closed {
|
||||
return 0, os.EINVAL
|
||||
return 0, os.ErrInvalid
|
||||
}
|
||||
b := make([]byte, len(s))
|
||||
copy(b, s)
|
||||
|
@ -121,9 +122,9 @@ func (m *mockNetConn) Write(s []byte) (int, os.Error) {
|
|||
return len(s), nil
|
||||
}
|
||||
|
||||
func (m *mockNetConn) Close() os.Error {
|
||||
func (m *mockNetConn) Close() error {
|
||||
if m.closed {
|
||||
return os.EINVAL
|
||||
return os.ErrInvalid
|
||||
}
|
||||
// Shut down *ALL* the goroutines!
|
||||
// This will trigger an EOF event in Read() too
|
||||
|
@ -142,18 +143,18 @@ func (m *mockNetConn) RemoteAddr() net.Addr {
|
|||
return &net.IPAddr{net.IPv4(127, 0, 0, 1)}
|
||||
}
|
||||
|
||||
func (m *mockNetConn) SetTimeout(ns int64) os.Error {
|
||||
m.rt = ns
|
||||
m.wt = ns
|
||||
func (m *mockNetConn) SetDeadline(t time.Time) error {
|
||||
m.rt = t
|
||||
m.wt = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockNetConn) SetReadTimeout(ns int64) os.Error {
|
||||
m.rt = ns
|
||||
func (m *mockNetConn) SetReadDeadline(t time.Time) error {
|
||||
m.rt = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *mockNetConn) SetWriteTimeout(ns int64) os.Error {
|
||||
m.wt = ns
|
||||
func (m *mockNetConn) SetWriteDeadline(t time.Time) error {
|
||||
m.wt = t
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@ import (
|
|||
type Channel struct {
|
||||
Name, Topic string
|
||||
Modes *ChanMode
|
||||
lookup map[string]*Nick
|
||||
lookup map[string]*Nick
|
||||
nicks map[*Nick]*ChanPrivs
|
||||
l logging.Logger
|
||||
l logging.Logger
|
||||
}
|
||||
|
||||
// A struct representing the modes of an IRC Channel
|
||||
|
@ -93,11 +93,11 @@ func init() {
|
|||
|
||||
func NewChannel(name string, l logging.Logger) *Channel {
|
||||
return &Channel{
|
||||
Name: name,
|
||||
Modes: new(ChanMode),
|
||||
nicks: make(map[*Nick]*ChanPrivs),
|
||||
Name: name,
|
||||
Modes: new(ChanMode),
|
||||
nicks: make(map[*Nick]*ChanPrivs),
|
||||
lookup: make(map[string]*Nick),
|
||||
l: l,
|
||||
l: l,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,8 +125,8 @@ func (ch *Channel) addNick(nk *Nick, cp *ChanPrivs) {
|
|||
// Disassociates a Nick from a Channel.
|
||||
func (ch *Channel) delNick(nk *Nick) {
|
||||
if _, ok := ch.nicks[nk]; ok {
|
||||
ch.nicks[nk] = nil, false
|
||||
ch.lookup[nk.Nick] = nil, false
|
||||
delete(ch.nicks, nk)
|
||||
delete(ch.lookup, nk.Nick)
|
||||
} else {
|
||||
ch.l.Warn("Channel.delNick(): %s not on %s.", nk.Nick, ch.Name)
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ func (ch *Channel) ParseModes(modes string, modeargs ...string) {
|
|||
}
|
||||
case 'q', 'a', 'o', 'h', 'v':
|
||||
if len(modeargs) != 0 {
|
||||
if nk, ok := ch.lookup[modeargs[0]]; ok {
|
||||
if nk, ok := ch.lookup[modeargs[0]]; ok {
|
||||
cp := ch.nicks[nk]
|
||||
switch m {
|
||||
case 'q':
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
gomock "gomock.googlecode.com/hg/gomock"
|
||||
gomock "github.com/dsymonds/gomock/gomock"
|
||||
)
|
||||
|
||||
// Mock of StateTracker interface
|
||||
|
@ -24,127 +24,127 @@ func NewMockStateTracker(ctrl *gomock.Controller) *MockStateTracker {
|
|||
return mock
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) EXPECT() *_MockStateTrackerRecorder {
|
||||
return m.recorder
|
||||
func (_m *MockStateTracker) EXPECT() *_MockStateTrackerRecorder {
|
||||
return _m.recorder
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) NewNick(nick string) *Nick {
|
||||
ret := m.ctrl.Call(m, "NewNick", nick)
|
||||
func (_m *MockStateTracker) NewNick(nick string) *Nick {
|
||||
ret := _m.ctrl.Call(_m, "NewNick", nick)
|
||||
ret0, _ := ret[0].(*Nick)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) NewNick(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "NewNick", arg0)
|
||||
func (_mr *_MockStateTrackerRecorder) NewNick(arg0 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "NewNick", arg0)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) GetNick(nick string) *Nick {
|
||||
ret := m.ctrl.Call(m, "GetNick", nick)
|
||||
func (_m *MockStateTracker) GetNick(nick string) *Nick {
|
||||
ret := _m.ctrl.Call(_m, "GetNick", nick)
|
||||
ret0, _ := ret[0].(*Nick)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) GetNick(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "GetNick", arg0)
|
||||
func (_mr *_MockStateTrackerRecorder) GetNick(arg0 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetNick", arg0)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) ReNick(old string, neu string) {
|
||||
m.ctrl.Call(m, "ReNick", old, neu)
|
||||
func (_m *MockStateTracker) ReNick(old string, neu string) {
|
||||
_m.ctrl.Call(_m, "ReNick", old, neu)
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) ReNick(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "ReNick", arg0, arg1)
|
||||
func (_mr *_MockStateTrackerRecorder) ReNick(arg0, arg1 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "ReNick", arg0, arg1)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) DelNick(nick string) {
|
||||
m.ctrl.Call(m, "DelNick", nick)
|
||||
func (_m *MockStateTracker) DelNick(nick string) {
|
||||
_m.ctrl.Call(_m, "DelNick", nick)
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) DelNick(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "DelNick", arg0)
|
||||
func (_mr *_MockStateTrackerRecorder) DelNick(arg0 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "DelNick", arg0)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) NewChannel(channel string) *Channel {
|
||||
ret := m.ctrl.Call(m, "NewChannel", channel)
|
||||
func (_m *MockStateTracker) NewChannel(channel string) *Channel {
|
||||
ret := _m.ctrl.Call(_m, "NewChannel", channel)
|
||||
ret0, _ := ret[0].(*Channel)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) NewChannel(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "NewChannel", arg0)
|
||||
func (_mr *_MockStateTrackerRecorder) NewChannel(arg0 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "NewChannel", arg0)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) GetChannel(channel string) *Channel {
|
||||
ret := m.ctrl.Call(m, "GetChannel", channel)
|
||||
func (_m *MockStateTracker) GetChannel(channel string) *Channel {
|
||||
ret := _m.ctrl.Call(_m, "GetChannel", channel)
|
||||
ret0, _ := ret[0].(*Channel)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) GetChannel(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "GetChannel", arg0)
|
||||
func (_mr *_MockStateTrackerRecorder) GetChannel(arg0 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "GetChannel", arg0)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) DelChannel(channel string) {
|
||||
m.ctrl.Call(m, "DelChannel", channel)
|
||||
func (_m *MockStateTracker) DelChannel(channel string) {
|
||||
_m.ctrl.Call(_m, "DelChannel", channel)
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) DelChannel(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "DelChannel", arg0)
|
||||
func (_mr *_MockStateTrackerRecorder) DelChannel(arg0 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "DelChannel", arg0)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) Me() *Nick {
|
||||
ret := m.ctrl.Call(m, "Me")
|
||||
func (_m *MockStateTracker) Me() *Nick {
|
||||
ret := _m.ctrl.Call(_m, "Me")
|
||||
ret0, _ := ret[0].(*Nick)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) Me() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "Me")
|
||||
func (_mr *_MockStateTrackerRecorder) Me() *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Me")
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) IsOn(channel string, nick string) (*ChanPrivs, bool) {
|
||||
ret := m.ctrl.Call(m, "IsOn", channel, nick)
|
||||
func (_m *MockStateTracker) IsOn(channel string, nick string) (*ChanPrivs, bool) {
|
||||
ret := _m.ctrl.Call(_m, "IsOn", channel, nick)
|
||||
ret0, _ := ret[0].(*ChanPrivs)
|
||||
ret1, _ := ret[1].(bool)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) IsOn(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "IsOn", arg0, arg1)
|
||||
func (_mr *_MockStateTrackerRecorder) IsOn(arg0, arg1 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "IsOn", arg0, arg1)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) Associate(channel *Channel, nick *Nick) *ChanPrivs {
|
||||
ret := m.ctrl.Call(m, "Associate", channel, nick)
|
||||
func (_m *MockStateTracker) Associate(channel *Channel, nick *Nick) *ChanPrivs {
|
||||
ret := _m.ctrl.Call(_m, "Associate", channel, nick)
|
||||
ret0, _ := ret[0].(*ChanPrivs)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) Associate(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "Associate", arg0, arg1)
|
||||
func (_mr *_MockStateTrackerRecorder) Associate(arg0, arg1 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Associate", arg0, arg1)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) Dissociate(channel *Channel, nick *Nick) {
|
||||
m.ctrl.Call(m, "Dissociate", channel, nick)
|
||||
func (_m *MockStateTracker) Dissociate(channel *Channel, nick *Nick) {
|
||||
_m.ctrl.Call(_m, "Dissociate", channel, nick)
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) Dissociate(arg0, arg1 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "Dissociate", arg0, arg1)
|
||||
func (_mr *_MockStateTrackerRecorder) Dissociate(arg0, arg1 interface{}) *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Dissociate", arg0, arg1)
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) Wipe() {
|
||||
m.ctrl.Call(m, "Wipe")
|
||||
func (_m *MockStateTracker) Wipe() {
|
||||
_m.ctrl.Call(_m, "Wipe")
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) Wipe() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "Wipe")
|
||||
func (_mr *_MockStateTrackerRecorder) Wipe() *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "Wipe")
|
||||
}
|
||||
|
||||
func (m *MockStateTracker) String() string {
|
||||
ret := m.ctrl.Call(m, "String")
|
||||
func (_m *MockStateTracker) String() string {
|
||||
ret := _m.ctrl.Call(_m, "String")
|
||||
ret0, _ := ret[0].(string)
|
||||
return ret0
|
||||
}
|
||||
|
||||
func (mr *_MockStateTrackerRecorder) String() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCall(mr.mock, "String")
|
||||
func (_mr *_MockStateTrackerRecorder) String() *gomock.Call {
|
||||
return _mr.mock.ctrl.RecordCall(_mr.mock, "String")
|
||||
}
|
||||
|
|
|
@ -9,9 +9,9 @@ import (
|
|||
type Nick struct {
|
||||
Nick, Ident, Host, Name string
|
||||
Modes *NickMode
|
||||
lookup map[string]*Channel
|
||||
lookup map[string]*Channel
|
||||
chans map[*Channel]*ChanPrivs
|
||||
l logging.Logger
|
||||
l logging.Logger
|
||||
}
|
||||
|
||||
// A struct representing the modes of an IRC Nick (User Modes)
|
||||
|
@ -46,11 +46,11 @@ func init() {
|
|||
|
||||
func NewNick(n string, l logging.Logger) *Nick {
|
||||
return &Nick{
|
||||
Nick: n,
|
||||
Modes: new(NickMode),
|
||||
chans: make(map[*Channel]*ChanPrivs),
|
||||
Nick: n,
|
||||
Modes: new(NickMode),
|
||||
chans: make(map[*Channel]*ChanPrivs),
|
||||
lookup: make(map[string]*Channel),
|
||||
l: l,
|
||||
l: l,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,8 +78,8 @@ func (nk *Nick) addChannel(ch *Channel, cp *ChanPrivs) {
|
|||
// Disassociates a Channel from a Nick.
|
||||
func (nk *Nick) delChannel(ch *Channel) {
|
||||
if _, ok := nk.chans[ch]; ok {
|
||||
nk.chans[ch] = nil, false
|
||||
nk.lookup[ch.Name] = nil, false
|
||||
delete(nk.chans, ch)
|
||||
delete(nk.lookup, ch.Name)
|
||||
} else {
|
||||
nk.l.Warn("Nick.delChannel(): %s not on %s.", nk.Nick, ch.Name)
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ func NewTracker(mynick string, l logging.Logger) *stateTracker {
|
|||
st := &stateTracker{
|
||||
chans: make(map[string]*Channel),
|
||||
nicks: make(map[string]*Nick),
|
||||
l: l,
|
||||
l: l,
|
||||
}
|
||||
st.me = st.NewNick(mynick)
|
||||
return st
|
||||
|
@ -88,12 +88,12 @@ func (st *stateTracker) ReNick(old, neu string) {
|
|||
if nk, ok := st.nicks[old]; ok {
|
||||
if _, ok := st.nicks[neu]; !ok {
|
||||
nk.Nick = neu
|
||||
st.nicks[old] = nil, false
|
||||
delete(st.nicks, old)
|
||||
st.nicks[neu] = nk
|
||||
for ch, _ := range nk.chans {
|
||||
// We also need to update the lookup maps of all the channels
|
||||
// the nick is on, to keep things in sync.
|
||||
ch.lookup[old] = nil, false
|
||||
delete(ch.lookup, old)
|
||||
ch.lookup[neu] = nk
|
||||
}
|
||||
} else {
|
||||
|
@ -123,7 +123,7 @@ func (st *stateTracker) delNick(nk *Nick) {
|
|||
st.l.Error("StateTracker.DelNick(): TRYING TO DELETE ME :-(")
|
||||
return
|
||||
}
|
||||
st.nicks[nk.Nick] = nil, false
|
||||
delete(st.nicks, nk.Nick)
|
||||
for ch, _ := range nk.chans {
|
||||
nk.delChannel(ch)
|
||||
ch.delNick(nk)
|
||||
|
@ -165,7 +165,7 @@ func (st *stateTracker) DelChannel(c string) {
|
|||
}
|
||||
|
||||
func (st *stateTracker) delChannel(ch *Channel) {
|
||||
st.chans[ch.Name] = nil, false
|
||||
delete(st.chans, ch.Name)
|
||||
for nk, _ := range ch.nicks {
|
||||
ch.delNick(nk)
|
||||
nk.delChannel(ch)
|
||||
|
|
|
@ -2,7 +2,7 @@ package state
|
|||
|
||||
import (
|
||||
"github.com/fluffle/golog/logging"
|
||||
"gomock.googlecode.com/hg/gomock"
|
||||
gomock "github.com/dsymonds/gomock/gomock"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
Loading…
Reference in New Issue