Tracking wip.

This commit is contained in:
Alex Bramley 2011-09-28 20:48:58 +01:00
parent c400a2141a
commit eb6ac4ce05
2 changed files with 64 additions and 29 deletions

View File

@ -27,10 +27,8 @@ type Conn struct {
Registry event.EventRegistry Registry event.EventRegistry
Dispatcher event.EventDispatcher Dispatcher event.EventDispatcher
// Map of channels we're on // State tracker for nicks and channels
chans map[string]*Channel Tracker StateTracker
// Map of nicks we know about
nicks map[string]*Nick
// Use the State field to store external state that handlers might need. // Use the State field to store external state that handlers might need.
// Remember ... you might need locking for this ;-) // Remember ... you might need locking for this ;-)

View File

@ -5,16 +5,41 @@ package client
import ( import (
"fmt" "fmt"
"os"
"reflect" "reflect"
"strconv" "strconv"
) )
// The state manager interface
type StateTracker interface {
NewNick(nick string) *Nick
GetNick(nick string) *Nick
NewChannel(channel string) *Channel
GetChannel(channel string) *Channel
IsOn(channel, nick string) bool
}
// ... and a struct to implement it
type stateTracker struct {
// Map of channels we're on
chans map[string]*Channel
// Map of nicks we know about
nicks map[string]*Nick
// A pointer to the connection whose state this tracks
conn *Conn
// Logging interface
l Logger
}
// A struct representing an IRC channel // A struct representing an IRC channel
type Channel struct { type Channel struct {
Name, Topic string Name, Topic string
Modes *ChanMode Modes *ChanMode
Nicks map[*Nick]*ChanPrivs Nicks map[*Nick]*ChanPrivs
conn *Conn st StateTracker
} }
// A struct representing an IRC nick // A struct representing an IRC nick
@ -22,7 +47,7 @@ type Nick struct {
Nick, Ident, Host, Name string Nick, Ident, Host, Name string
Modes *NickMode Modes *NickMode
Channels map[*Channel]*ChanPrivs Channels map[*Channel]*ChanPrivs
conn *Conn st StateTracker
} }
// A struct representing the modes of an IRC Channel // A struct representing the modes of an IRC Channel
@ -60,45 +85,46 @@ type ChanPrivs struct {
} }
/******************************************************************************\ /******************************************************************************\
* Conn methods to create/look up nicks/channels * tracker methods to create/look up nicks/channels
\******************************************************************************/ \******************************************************************************/
// Creates a new *irc.Nick, initialises it, and stores it in *irc.Conn so it // Creates a new *irc.Nick, initialises it, and stores it so it
// can be properly tracked for state management purposes. // can be properly tracked for state management purposes.
func (conn *Conn) NewNick(nick, ident, name, host string) *Nick { func (st *stateTracker) NewNick(nick string) *Nick {
n := &Nick{Nick: nick, Ident: ident, Name: name, Host: host, conn: conn} n := &Nick{Nick: nick, st: st}
n.initialise() n.initialise()
conn.nicks[n.Nick] = n st.nicks[nick] = n
return n return n
} }
// Returns an *irc.Nick for the nick n, if we're tracking it. // Returns an *irc.Nick for the nick n, if we're tracking it.
func (conn *Conn) GetNick(n string) *Nick { func (st *stateTracker) GetNick(n string) *Nick {
if nick, ok := conn.nicks[n]; ok { if nick, ok := st.nicks[n]; ok {
return nick return nick
} }
return nil return nil
} }
// Creates a new *irc.Channel, initialises it, and stores it in *irc.Conn so it // Creates a new *irc.Channel, initialises it, and stores it so it
// can be properly tracked for state management purposes. // can be properly tracked for state management purposes.
func (conn *Conn) NewChannel(c string) *Channel { func (st *stateTracker) NewChannel(c string) *Channel {
ch := &Channel{Name: c, conn: conn} ch := &Channel{Name: c, st: st}
ch.initialise() ch.initialise()
conn.chans[ch.Name] = ch st.chans[c] = ch
return ch return ch
} }
// Returns an *irc.Channel for the channel c, if we're tracking it. // Returns an *irc.Channel for the channel c, if we're tracking it.
func (conn *Conn) GetChannel(c string) *Channel { func (st *stateTracker) GetChannel(c string) *Channel {
if ch, ok := conn.chans[c]; ok { if ch, ok := st.chans[c]; ok {
return ch return ch
} }
return nil return nil
} }
// Parses mode strings for a channel // Parses mode strings for a channel
func (conn *Conn) ParseChannelModes(ch *Channel, modes string, modeargs []string) { func (ch *Channel) ParseModes(modes string, modeargs []string) os.Error {
var modeop bool // true => add mode, false => remove mode var modeop bool // true => add mode, false => remove mode
var modestr string var modestr string
for i := 0; i < len(modes); i++ { for i := 0; i < len(modes); i++ {
@ -126,21 +152,29 @@ func (conn *Conn) ParseChannelModes(ch *Channel, modes string, modeargs []string
case 'O': case 'O':
ch.Modes.OperOnly = modeop ch.Modes.OperOnly = modeop
case 'k': case 'k':
if len(modeargs) != 0 { if modeop && len(modeargs) != 0 {
ch.Modes.Key, modeargs = modeargs[0], modeargs[1:] ch.Modes.Key, modeargs = modeargs[0], modeargs[1:]
} else if !modeop {
ch.Modes.Key = ""
} else { } else {
conn.error("irc.ParseChanModes(): buh? not enough arguments to process MODE %s %s%s", ch.Name, modestr, m) return os.NewError(fmt.Sprintf(
"irc.ParseChanModes(): buh? not enough arguments to process MODE %s %s%s",
ch.Name, modestr, m))
} }
case 'l': case 'l':
if len(modeargs) != 0 { if modeop && len(modeargs) != 0 {
ch.Modes.Limit, _ = strconv.Atoi(modeargs[0]) ch.Modes.Limit, _ = strconv.Atoi(modeargs[0])
modeargs = modeargs[1:] modeargs = modeargs[1:]
} else { } else if !modeop {
conn.error("irc.ParseChanModes(): buh? not enough arguments to process MODE %s %s%s", ch.Name, modestr, m) ch.Modes.Limit = 0
}
return os.NewError(fmt.Sprintf(
"Channel.ParseModes(): buh? not enough arguments to process MODE %s %s%s",
ch.Name, modestr, m))
} }
case 'q', 'a', 'o', 'h', 'v': case 'q', 'a', 'o', 'h', 'v':
if len(modeargs) != 0 { if len(modeargs) != 0 {
n := conn.GetNick(modeargs[0]) n := ch.st.GetNick(modeargs[0])
if p, ok := ch.Nicks[n]; ok && n != nil { if p, ok := ch.Nicks[n]; ok && n != nil {
switch m { switch m {
case 'q': case 'q':
@ -156,17 +190,20 @@ func (conn *Conn) ParseChannelModes(ch *Channel, modes string, modeargs []string
} }
modeargs = modeargs[1:] modeargs = modeargs[1:]
} else { } else {
conn.error("irc.ParseChanModes(): MODE %s %s%s %s: buh? state tracking failure.", ch.Name, modestr, m, modeargs[0]) return os.NewError(fmt.Sprintf(
"Channel.ParseModes(): MODE %s %s%s %s: buh? state tracking failure.",
ch.Name, modestr, m, modeargs[0]))
} }
} else { } else {
conn.error("irc.ParseChanModes(): buh? not enough arguments to process MODE %s %s%s", ch.Name, modestr, m) conn.error("Channel.ParseModes(): buh? not enough arguments to process MODE %s %s%s", ch.Name, modestr, m)
} }
} }
} }
return nil
} }
// Parse mode strings for a nick // Parse mode strings for a nick
func (conn *Conn) ParseNickModes(n *Nick, modes string) { func (n *Nick) ParseModes(modes string) {
var modeop bool // true => add mode, false => remove mode var modeop bool // true => add mode, false => remove mode
for i := 0; i < len(modes); i++ { for i := 0; i < len(modes); i++ {
switch m := modes[i]; m { switch m := modes[i]; m {