mirror of
				https://github.com/fluffle/goirc
				synced 2025-10-31 02:08:03 +00:00 
			
		
		
		
	Handlers/Commands now use the container/list.
Re introduced strip nick and strip prefix for SimpleCommands Fixed tests.
This commit is contained in:
		
							parent
							
								
									e8eba53828
								
							
						
					
					
						commit
						e4da830c55
					
				
					 5 changed files with 134 additions and 208 deletions
				
			
		|  | @ -21,7 +21,7 @@ type Conn struct { | ||||||
| 	password string | 	password string | ||||||
| 
 | 
 | ||||||
| 	// Handlers and Commands | 	// Handlers and Commands | ||||||
| 	handlers *hSet | 	handlers *handlerSet | ||||||
| 	commands *commandList | 	commands *commandList | ||||||
| 
 | 
 | ||||||
| 	// State tracker for nicks and channels | 	// State tracker for nicks and channels | ||||||
|  | @ -54,6 +54,9 @@ type Conn struct { | ||||||
| 	// Client->server ping frequency, in seconds. Defaults to 3m. | 	// Client->server ping frequency, in seconds. Defaults to 3m. | ||||||
| 	PingFreq time.Duration | 	PingFreq time.Duration | ||||||
| 
 | 
 | ||||||
|  | 	// Controls what is stripped from line.Args[1] for Commands | ||||||
|  | 	CommandStripNick, SimpleCommandStripPrefix bool | ||||||
|  | 
 | ||||||
| 	// Set this to true to disable flood protection and false to re-enable | 	// Set this to true to disable flood protection and false to re-enable | ||||||
| 	Flood bool | 	Flood bool | ||||||
| 
 | 
 | ||||||
|  | @ -81,7 +84,7 @@ func Client(nick string, args ...string) *Conn { | ||||||
| 		cSend:      make(chan bool), | 		cSend:      make(chan bool), | ||||||
| 		cLoop:      make(chan bool), | 		cLoop:      make(chan bool), | ||||||
| 		cPing:      make(chan bool), | 		cPing:      make(chan bool), | ||||||
| 		handlers:   handlerSet(), | 		handlers:   newHandlerSet(), | ||||||
| 		commands:   newCommandList(), | 		commands:   newCommandList(), | ||||||
| 		stRemovers: make([]Remover, 0, len(stHandlers)), | 		stRemovers: make([]Remover, 0, len(stHandlers)), | ||||||
| 		PingFreq:   3 * time.Minute, | 		PingFreq:   3 * time.Minute, | ||||||
|  |  | ||||||
|  | @ -1,6 +1,7 @@ | ||||||
| package client | package client | ||||||
| 
 | 
 | ||||||
| import ( | import ( | ||||||
|  | 	"container/list" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/fluffle/golog/logging" | 	"github.com/fluffle/golog/logging" | ||||||
| 	"math" | 	"math" | ||||||
|  | @ -31,163 +32,119 @@ func (r RemoverFunc) Remove() { | ||||||
| 	r() | 	r() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type hList struct { | type handlerElement struct { | ||||||
| 	start, end *hNode |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type hNode struct { |  | ||||||
| 	next, prev *hNode |  | ||||||
| 	set        *hSet |  | ||||||
| 	event   string | 	event   string | ||||||
| 	handler Handler | 	handler Handler | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (hn *hNode) Handle(conn *Conn, line *Line) { | type handlerSet struct { | ||||||
| 	hn.handler.Handle(conn, line) | 	set map[string]*list.List | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (hn *hNode) Remove() { |  | ||||||
| 	hn.set.remove(hn) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type hSet struct { |  | ||||||
| 	set map[string]*hList |  | ||||||
| 	sync.RWMutex | 	sync.RWMutex | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func handlerSet() *hSet { | func newHandlerSet() *handlerSet { | ||||||
| 	return &hSet{set: make(map[string]*hList)} | 	return &handlerSet{set: make(map[string]*list.List)} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (hs *hSet) add(ev string, h Handler) Remover { | func (hs *handlerSet) add(event string, handler Handler) Remover { | ||||||
| 	hs.Lock() | 	hs.Lock() | ||||||
| 	defer hs.Unlock() | 	defer hs.Unlock() | ||||||
| 	ev = strings.ToLower(ev) | 	event = strings.ToLower(event) | ||||||
| 	l, ok := hs.set[ev] | 	l, ok := hs.set[event] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		l = &hList{} | 		l = list.New() | ||||||
|  | 		hs.set[event] = l | ||||||
| 	} | 	} | ||||||
| 	hn := &hNode{ | 	element := l.PushBack(&handlerElement{event, handler}) | ||||||
| 		set:     hs, | 	return RemoverFunc(func() { | ||||||
| 		event:   ev, | 		hs.remove(element) | ||||||
| 		handler: h, | 	}) | ||||||
| 	} |  | ||||||
| 	if !ok { |  | ||||||
| 		l.start = hn |  | ||||||
| 	} else { |  | ||||||
| 		hn.prev = l.end |  | ||||||
| 		l.end.next = hn |  | ||||||
| 	} |  | ||||||
| 	l.end = hn |  | ||||||
| 	hs.set[ev] = l |  | ||||||
| 	return hn |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (hs *hSet) remove(hn *hNode) { | func (hs *handlerSet) remove(element *list.Element) { | ||||||
| 	hs.Lock() | 	hs.Lock() | ||||||
| 	defer hs.Unlock() | 	defer hs.Unlock() | ||||||
| 	l, ok := hs.set[hn.event] | 	h := element.Value.(*handlerElement) | ||||||
|  | 	l, ok := hs.set[h.event] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		logging.Error("Removing node for unknown event '%s'", hn.event) | 		logging.Error("Removing node for unknown event '%s'", h.event) | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	if hn.next == nil { | 	l.Remove(element) | ||||||
| 		l.end = hn.prev | 	if l.Len() == 0 { | ||||||
| 	} else { | 		delete(hs.set, h.event) | ||||||
| 		hn.next.prev = hn.prev |  | ||||||
| 	} |  | ||||||
| 	if hn.prev == nil { |  | ||||||
| 		l.start = hn.next |  | ||||||
| 	} else { |  | ||||||
| 		hn.prev.next = hn.next |  | ||||||
| 	} |  | ||||||
| 	hn.next = nil |  | ||||||
| 	hn.prev = nil |  | ||||||
| 	hn.set = nil |  | ||||||
| 	if l.start == nil || l.end == nil { |  | ||||||
| 		delete(hs.set, hn.event) |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (hs *hSet) dispatch(conn *Conn, line *Line) { | func (hs *handlerSet) dispatch(conn *Conn, line *Line) { | ||||||
| 	hs.RLock() | 	hs.RLock() | ||||||
| 	defer hs.RUnlock() | 	defer hs.RUnlock() | ||||||
| 	ev := strings.ToLower(line.Cmd) | 	event := strings.ToLower(line.Cmd) | ||||||
| 	list, ok := hs.set[ev] | 	l, ok := hs.set[event] | ||||||
| 	if !ok { | 	if !ok { | ||||||
| 		return | 		return | ||||||
| 	} | 	} | ||||||
| 	for hn := list.start; hn != nil; hn = hn.next { | 
 | ||||||
| 		go hn.Handle(conn, line) | 	for e := l.Front(); e != nil; e = e.Next() { | ||||||
|  | 		h := e.Value.(*handlerElement) | ||||||
|  | 		go h.handler.Handle(conn, line) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| type command struct { | type commandElement struct { | ||||||
| 	handler  Handler |  | ||||||
| 	set      *commandList |  | ||||||
| 	regex    string | 	regex    string | ||||||
|  | 	handler  Handler | ||||||
| 	priority int | 	priority int | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (c *command) Handle(conn *Conn, line *Line) { |  | ||||||
| 	c.handler.Handle(conn, line) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| func (c *command) Remove() { |  | ||||||
| 	c.set.remove(c) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| type commandList struct { | type commandList struct { | ||||||
| 	set []*command | 	list *list.List | ||||||
| 	sync.RWMutex | 	sync.RWMutex | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func newCommandList() *commandList { | func newCommandList() *commandList { | ||||||
| 	return &commandList{} | 	return &commandList{list: list.New()} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (cl *commandList) add(regex string, handler Handler, priority int) Remover { | func (cl *commandList) add(regex string, handler Handler, priority int) Remover { | ||||||
| 	cl.Lock() | 	cl.Lock() | ||||||
| 	defer cl.Unlock() | 	defer cl.Unlock() | ||||||
| 	c := &command{ | 	c := &commandElement{ | ||||||
| 		handler:  handler, |  | ||||||
| 		set:      cl, |  | ||||||
| 		regex:    regex, | 		regex:    regex, | ||||||
|  | 		handler:  handler, | ||||||
| 		priority: priority, | 		priority: priority, | ||||||
| 	} | 	} | ||||||
| 	// Check for exact regex matches. This will filter out any repeated SimpleCommands. | 	// Check for exact regex matches. This will filter out any repeated SimpleCommands. | ||||||
| 	for _, c := range cl.set { | 	for e := cl.list.Front(); e != nil; e = e.Next() { | ||||||
|  | 		c := e.Value.(*commandElement) | ||||||
| 		if c.regex == regex { | 		if c.regex == regex { | ||||||
| 			logging.Error("Command prefix '%s' already registered.", regex) | 			logging.Error("Command prefix '%s' already registered.", regex) | ||||||
| 			return nil | 			return nil | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	cl.set = append(cl.set, c) | 	element := cl.list.PushBack(c) | ||||||
| 	return c | 	return RemoverFunc(func() { | ||||||
|  | 		cl.remove(element) | ||||||
|  | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (cl *commandList) remove(c *command) { | func (cl *commandList) remove(element *list.Element) { | ||||||
| 	cl.Lock() | 	cl.Lock() | ||||||
| 	defer cl.Unlock() | 	defer cl.Unlock() | ||||||
| 	for index, value := range cl.set { | 	cl.list.Remove(element) | ||||||
| 		if value == c { |  | ||||||
| 			copy(cl.set[index:], cl.set[index+1:]) |  | ||||||
| 			cl.set = cl.set[:len(cl.set)-1] |  | ||||||
| 			c.set = nil |  | ||||||
| 			return |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // Matches the command with the highest priority. | // Matches the command with the highest priority. | ||||||
| func (cl *commandList) match(txt string) (handler Handler) { | func (cl *commandList) match(text string) (handler Handler) { | ||||||
| 	cl.RLock() | 	cl.RLock() | ||||||
| 	defer cl.RUnlock() | 	defer cl.RUnlock() | ||||||
| 	maxPriority := math.MinInt32 | 	maxPriority := math.MinInt32 | ||||||
| 	for _, c := range cl.set { | 	text = strings.ToLower(text) | ||||||
|  | 	for e := cl.list.Front(); e != nil; e = e.Next() { | ||||||
|  | 		c := e.Value.(*commandElement) | ||||||
| 		if c.priority > maxPriority { | 		if c.priority > maxPriority { | ||||||
| 			if regex, error := regexp.Compile(c.regex); error == nil { | 			if regex, error := regexp.Compile(c.regex); error == nil { | ||||||
| 				if regex.MatchString(txt) { | 				if regex.MatchString(text) { | ||||||
| 					maxPriority = c.priority | 					maxPriority = c.priority | ||||||
| 					handler = c.handler | 					handler = c.handler | ||||||
| 				} | 				} | ||||||
|  | @ -226,7 +183,18 @@ var SimpleCommandRegex string = `^!%v(\s|$)` | ||||||
| // !roll | // !roll | ||||||
| // Because simple commands are simple, they get the highest priority. | // Because simple commands are simple, they get the highest priority. | ||||||
| func (conn *Conn) SimpleCommand(prefix string, handler Handler) Remover { | func (conn *Conn) SimpleCommand(prefix string, handler Handler) Remover { | ||||||
| 	return conn.Command(fmt.Sprintf(SimpleCommandRegex, strings.ToLower(prefix)), handler, math.MaxInt32) | 	stripHandler := func(conn *Conn, line *Line) { | ||||||
|  | 		text := line.Message() | ||||||
|  | 		if conn.SimpleCommandStripPrefix { | ||||||
|  | 			text = strings.TrimSpace(text[len(prefix):]) | ||||||
|  | 		} | ||||||
|  | 		if text != line.Message() { | ||||||
|  | 			line = line.Copy() | ||||||
|  | 			line.Args[1] = text | ||||||
|  | 		} | ||||||
|  | 		handler.Handle(conn, line) | ||||||
|  | 	} | ||||||
|  | 	return conn.Command(fmt.Sprintf(SimpleCommandRegex, strings.ToLower(prefix)), HandlerFunc(stripHandler), math.MaxInt32) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (conn *Conn) SimpleCommandFunc(prefix string, handlerFunc HandlerFunc) Remover { | func (conn *Conn) SimpleCommandFunc(prefix string, handlerFunc HandlerFunc) Remover { | ||||||
|  | @ -256,10 +224,6 @@ func (conn *Conn) dispatch(line *Line) { | ||||||
| 	conn.handlers.dispatch(conn, line) | 	conn.handlers.dispatch(conn, line) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (conn *Conn) command(line *Line) { | func (conn *Conn) command(line *Line) Handler { | ||||||
| 	command := conn.commands.match(strings.ToLower(line.Message())) | 	return conn.commands.match(line.Message()) | ||||||
| 	if command != nil { |  | ||||||
| 		command.Handle(conn, line) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -6,7 +6,7 @@ import ( | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| func TestHandlerSet(t *testing.T) { | func TestHandlerSet(t *testing.T) { | ||||||
| 	hs := handlerSet() | 	hs := newHandlerSet() | ||||||
| 	if len(hs.set) != 0 { | 	if len(hs.set) != 0 { | ||||||
| 		t.Errorf("New set contains things!") | 		t.Errorf("New set contains things!") | ||||||
| 	} | 	} | ||||||
|  | @ -17,66 +17,40 @@ func TestHandlerSet(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Add one | 	// Add one | ||||||
| 	hn1 := hs.add("ONE", HandlerFunc(f)).(*hNode) | 	hn1 := hs.add("ONE", HandlerFunc(f)) | ||||||
| 	hl, ok := hs.set["one"] | 	hl, ok := hs.set["one"] | ||||||
| 	if len(hs.set) != 1 || !ok { | 	if len(hs.set) != 1 || !ok { | ||||||
| 		t.Errorf("Set doesn't contain 'one' list after add().") | 		t.Errorf("Set doesn't contain 'one' list after add().") | ||||||
| 	} | 	} | ||||||
| 	if hn1.set != hs || hn1.event != "one" || hn1.prev != nil || hn1.next != nil { | 	if hl.Len() != 1 { | ||||||
| 		t.Errorf("First node for 'one' not created correctly") | 		t.Errorf("List doesn't contain 'one' after add().") | ||||||
| 	} |  | ||||||
| 	if hl.start != hn1 || hl.end != hn1 { |  | ||||||
| 		t.Errorf("Node not added to empty 'one' list correctly.") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Add another one... | 	// Add another one... | ||||||
| 	hn2 := hs.add("one", HandlerFunc(f)).(*hNode) | 	hn2 := hs.add("one", HandlerFunc(f)) | ||||||
| 	if len(hs.set) != 1 { | 	if len(hs.set) != 1 { | ||||||
| 		t.Errorf("Set contains more than 'one' list after add().") | 		t.Errorf("Set contains more than 'one' list after add().") | ||||||
| 	} | 	} | ||||||
| 	if hn2.set != hs || hn2.event != "one" { | 	if hl.Len() != 2 { | ||||||
| 		t.Errorf("Second node for 'one' not created correctly") | 		t.Errorf("List doesn't contain second 'one' after add().") | ||||||
| 	} |  | ||||||
| 	if hn1.prev != nil || hn1.next != hn2 || hn2.prev != hn1 || hn2.next != nil { |  | ||||||
| 		t.Errorf("Nodes for 'one' not linked correctly.") |  | ||||||
| 	} |  | ||||||
| 	if hl.start != hn1 || hl.end != hn2 { |  | ||||||
| 		t.Errorf("Node not appended to 'one' list correctly.") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Add a third one! | 	// Add a third one! | ||||||
| 	hn3 := hs.add("one", HandlerFunc(f)).(*hNode) | 	hn3 := hs.add("one", HandlerFunc(f)) | ||||||
| 	if len(hs.set) != 1 { | 	if len(hs.set) != 1 { | ||||||
| 		t.Errorf("Set contains more than 'one' list after add().") | 		t.Errorf("Set contains more than 'one' list after add().") | ||||||
| 	} | 	} | ||||||
| 	if hn3.set != hs || hn3.event != "one" { | 	if hl.Len() != 3 { | ||||||
| 		t.Errorf("Third node for 'one' not created correctly") | 		t.Errorf("List doesn't contain third 'one' after add().") | ||||||
| 	} |  | ||||||
| 	if hn1.prev != nil || hn1.next != hn2 || |  | ||||||
| 		hn2.prev != hn1 || hn2.next != hn3 || |  | ||||||
| 		hn3.prev != hn2 || hn3.next != nil { |  | ||||||
| 		t.Errorf("Nodes for 'one' not linked correctly.") |  | ||||||
| 	} |  | ||||||
| 	if hl.start != hn1 || hl.end != hn3 { |  | ||||||
| 		t.Errorf("Node not appended to 'one' list correctly.") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// And finally a fourth one! | 	// And finally a fourth one! | ||||||
| 	hn4 := hs.add("one", HandlerFunc(f)).(*hNode) | 	hn4 := hs.add("one", HandlerFunc(f)) | ||||||
| 	if len(hs.set) != 1 { | 	if len(hs.set) != 1 { | ||||||
| 		t.Errorf("Set contains more than 'one' list after add().") | 		t.Errorf("Set contains more than 'one' list after add().") | ||||||
| 	} | 	} | ||||||
| 	if hn4.set != hs || hn4.event != "one" { | 	if hl.Len() != 4 { | ||||||
| 		t.Errorf("Fourth node for 'one' not created correctly.") | 		t.Errorf("List doesn't contain fourth 'one' after add().") | ||||||
| 	} |  | ||||||
| 	if hn1.prev != nil || hn1.next != hn2 || |  | ||||||
| 		hn2.prev != hn1 || hn2.next != hn3 || |  | ||||||
| 		hn3.prev != hn2 || hn3.next != hn4 || |  | ||||||
| 		hn4.prev != hn3 || hn4.next != nil { |  | ||||||
| 		t.Errorf("Nodes for 'one' not linked correctly.") |  | ||||||
| 	} |  | ||||||
| 	if hl.start != hn1 || hl.end != hn4 { |  | ||||||
| 		t.Errorf("Node not appended to 'one' list correctly.") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Dispatch should result in 4 additions. | 	// Dispatch should result in 4 additions. | ||||||
|  | @ -94,16 +68,8 @@ func TestHandlerSet(t *testing.T) { | ||||||
| 	if len(hs.set) != 1 { | 	if len(hs.set) != 1 { | ||||||
| 		t.Errorf("Set list count changed after remove().") | 		t.Errorf("Set list count changed after remove().") | ||||||
| 	} | 	} | ||||||
| 	if hn3.set != nil || hn3.prev != nil || hn3.next != nil { | 	if hl.Len() != 3 { | ||||||
| 		t.Errorf("Third node for 'one' not removed correctly.") | 		t.Errorf("Third 'one' not removed correctly.") | ||||||
| 	} |  | ||||||
| 	if hn1.prev != nil || hn1.next != hn2 || |  | ||||||
| 		hn2.prev != hn1 || hn2.next != hn4 || |  | ||||||
| 		hn4.prev != hn2 || hn4.next != nil { |  | ||||||
| 		t.Errorf("Third node for 'one' not unlinked correctly.") |  | ||||||
| 	} |  | ||||||
| 	if hl.start != hn1 || hl.end != hn4 { |  | ||||||
| 		t.Errorf("Third node for 'one' changed list pointers.") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Dispatch should result in 3 additions. | 	// Dispatch should result in 3 additions. | ||||||
|  | @ -114,18 +80,12 @@ func TestHandlerSet(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Remove node 1. | 	// Remove node 1. | ||||||
| 	hs.remove(hn1) | 	hn1.Remove() | ||||||
| 	if len(hs.set) != 1 { | 	if len(hs.set) != 1 { | ||||||
| 		t.Errorf("Set list count changed after remove().") | 		t.Errorf("Set list count changed after remove().") | ||||||
| 	} | 	} | ||||||
| 	if hn1.set != nil || hn1.prev != nil || hn1.next != nil { | 	if hl.Len() != 2 { | ||||||
| 		t.Errorf("First node for 'one' not removed correctly.") | 		t.Errorf("First 'one' not removed correctly.") | ||||||
| 	} |  | ||||||
| 	if hn2.prev != nil || hn2.next != hn4 || hn4.prev != hn2 || hn4.next != nil { |  | ||||||
| 		t.Errorf("First node for 'one' not unlinked correctly.") |  | ||||||
| 	} |  | ||||||
| 	if hl.start != hn2 || hl.end != hn4 { |  | ||||||
| 		t.Errorf("First node for 'one' didn't change list pointers.") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Dispatch should result in 2 additions. | 	// Dispatch should result in 2 additions. | ||||||
|  | @ -140,14 +100,8 @@ func TestHandlerSet(t *testing.T) { | ||||||
| 	if len(hs.set) != 1 { | 	if len(hs.set) != 1 { | ||||||
| 		t.Errorf("Set list count changed after remove().") | 		t.Errorf("Set list count changed after remove().") | ||||||
| 	} | 	} | ||||||
| 	if hn4.set != nil || hn4.prev != nil || hn4.next != nil { | 	if hl.Len() != 1 { | ||||||
| 		t.Errorf("Fourth node for 'one' not removed correctly.") | 		t.Errorf("Fourth 'one' not removed correctly.") | ||||||
| 	} |  | ||||||
| 	if hn2.prev != nil || hn2.next != nil { |  | ||||||
| 		t.Errorf("Fourth node for 'one' not unlinked correctly.") |  | ||||||
| 	} |  | ||||||
| 	if hl.start != hn2 || hl.end != hn2 { |  | ||||||
| 		t.Errorf("Fourth node for 'one' didn't change list pointers.") |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Dispatch should result in 1 addition. | 	// Dispatch should result in 1 addition. | ||||||
|  | @ -158,16 +112,10 @@ func TestHandlerSet(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Remove node 2. | 	// Remove node 2. | ||||||
| 	hs.remove(hn2) | 	hn2.Remove() | ||||||
| 	if len(hs.set) != 0 { | 	if len(hs.set) != 0 { | ||||||
| 		t.Errorf("Removing last node in 'one' didn't remove list.") | 		t.Errorf("Removing last node in 'one' didn't remove list.") | ||||||
| 	} | 	} | ||||||
| 	if hn2.set != nil || hn2.prev != nil || hn2.next != nil { |  | ||||||
| 		t.Errorf("Second node for 'one' not removed correctly.") |  | ||||||
| 	} |  | ||||||
| 	if hl.start != nil || hl.end != nil { |  | ||||||
| 		t.Errorf("Second node for 'one' didn't change list pointers.") |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
| 	// Dispatch should result in NO additions. | 	// Dispatch should result in NO additions. | ||||||
| 	hs.dispatch(nil, &Line{Cmd: "One"}) | 	hs.dispatch(nil, &Line{Cmd: "One"}) | ||||||
|  | @ -178,52 +126,43 @@ func TestHandlerSet(t *testing.T) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func TestCommandSet(t *testing.T) { | func TestCommandSet(t *testing.T) { | ||||||
| 	cs := commandSet() | 	cl := newCommandList() | ||||||
| 	if len(cs.set) != 0 { | 	if cl.list.Len() != 0 { | ||||||
| 		t.Errorf("New set contains things!") | 		t.Errorf("New list contains things!") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	c := &command{ | 	cn1 := cl.add("one", HandlerFunc(func(c *Conn, l *Line) {}), 0) | ||||||
| 		fn:   func(c *Conn, l *Line) {}, | 	if cl.list.Len() != 1 { | ||||||
| 		help: "wtf?", | 		t.Errorf("Command 'one' not added to list correctly.") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cn1 := cs.add("ONE", c).(*cNode) | 	cn2 := cl.add("one two", HandlerFunc(func(c *Conn, l *Line) {}), 0) | ||||||
| 	if _, ok := cs.set["one"]; !ok || cn1.set != cs || cn1.prefix != "one" { | 	if cl.list.Len() != 2 { | ||||||
| 		t.Errorf("Command 'one' not added to set correctly.") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	if fail := cs.add("one", c); fail != nil { |  | ||||||
| 		t.Errorf("Adding a second 'one' command did not fail as expected.") |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	cn2 := cs.add("One Two", c).(*cNode) |  | ||||||
| 	if _, ok := cs.set["one two"]; !ok || cn2.set != cs || cn2.prefix != "one two" { |  | ||||||
| 		t.Errorf("Command 'one two' not added to set correctly.") | 		t.Errorf("Command 'one two' not added to set correctly.") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if c, l := cs.match("foo"); c != nil || l != 0 { | 	if c := cl.match("foo"); c != nil { | ||||||
| 		t.Errorf("Matched 'foo' when we shouldn't.") | 		t.Errorf("Matched 'foo' when we shouldn't.") | ||||||
| 	} | 	} | ||||||
| 	if c, l := cs.match("one"); c.(*cNode) != cn1 || l != 3 { | 	if c := cl.match("one"); c == nil { | ||||||
| 		t.Errorf("Didn't match 'one' when we should have.") | 		t.Errorf("Didn't match when we should have.") | ||||||
| 	} | 	} | ||||||
| 	if c, l := cs.match("one two three"); c.(*cNode) != cn2 || l != 7 { | 	if c := cl.match("one two three"); c == nil { | ||||||
| 		t.Errorf("Didn't match 'one two' when we should have.") | 		t.Errorf("Didn't match when we should have.") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	cs.remove(cn2) | 	cn2.Remove() | ||||||
| 	if _, ok := cs.set["one two"]; ok || cn2.set != nil { | 	if cl.list.Len() != 1 { | ||||||
| 		t.Errorf("Command 'one two' not removed correctly.") | 		t.Errorf("Command 'one two' not removed correctly.") | ||||||
| 	} | 	} | ||||||
| 	if c, l := cs.match("one two three"); c.(*cNode) != cn1 || l != 3 { | 	if c := cl.match("one two three"); c == nil { | ||||||
| 		t.Errorf("Didn't match 'one' when we should have.") | 		t.Errorf("Didn't match when we should have.") | ||||||
| 	} | 	} | ||||||
| 	cn1.Remove() | 	cn1.Remove() | ||||||
| 	if _, ok := cs.set["one"]; ok || cn1.set != nil { | 	if cl.list.Len() != 0 { | ||||||
| 		t.Errorf("Command 'one' not removed correctly.") | 		t.Errorf("Command 'one two' not removed correctly.") | ||||||
| 	} | 	} | ||||||
| 	if c, l := cs.match("one two three"); c != nil || l != 0 { | 	if c := cl.match("one two three"); c != nil { | ||||||
| 		t.Errorf("Matched 'one' when we shouldn't have.") | 		t.Errorf("Matched 'one' when we shouldn't.") | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -97,5 +97,23 @@ func (conn *Conn) h_NICK(line *Line) { | ||||||
| 
 | 
 | ||||||
| // Handle PRIVMSGs that trigger Commands | // Handle PRIVMSGs that trigger Commands | ||||||
| func (conn *Conn) h_PRIVMSG(line *Line) { | func (conn *Conn) h_PRIVMSG(line *Line) { | ||||||
| 	conn.command(line) | 	text := line.Message() | ||||||
|  | 	if conn.CommandStripNick && strings.HasPrefix(text, conn.Me.Nick) { | ||||||
|  | 		// Look for '^${nick}[:;>,-]? ' | ||||||
|  | 		l := len(conn.Me.Nick) | ||||||
|  | 		switch text[l] { | ||||||
|  | 		case ':', ';', '>', ',', '-': | ||||||
|  | 			l++ | ||||||
|  | 		} | ||||||
|  | 		if text[l] == ' ' { | ||||||
|  | 			text = strings.TrimSpace(text[l:]) | ||||||
|  | 		} | ||||||
|  | 		line = line.Copy() | ||||||
|  | 		line.Args[1] = text | ||||||
|  | 	} | ||||||
|  | 	cmd := conn.command(line) | ||||||
|  | 	if cmd == nil { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 	cmd.Handle(conn, line) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -146,7 +146,9 @@ func TestPRIVMSG(t *testing.T) { | ||||||
| 	f := func(conn *Conn, line *Line) { | 	f := func(conn *Conn, line *Line) { | ||||||
| 		conn.Privmsg(line.Args[0], line.Args[1]) | 		conn.Privmsg(line.Args[0], line.Args[1]) | ||||||
| 	} | 	} | ||||||
| 	c.CommandFunc("prefix", f, "") | 	// Test legacy simpleCommands, with out the !. | ||||||
|  | 	SimpleCommandRegex = `^%v(\s|$)` | ||||||
|  | 	c.SimpleCommandFunc("prefix", f) | ||||||
| 
 | 
 | ||||||
| 	// CommandStripNick and CommandStripPrefix are both false to begin | 	// CommandStripNick and CommandStripPrefix are both false to begin | ||||||
| 	c.h_PRIVMSG(parseLine(":blah!moo@cows.com PRIVMSG #foo :prefix bar")) | 	c.h_PRIVMSG(parseLine(":blah!moo@cows.com PRIVMSG #foo :prefix bar")) | ||||||
|  | @ -163,7 +165,7 @@ func TestPRIVMSG(t *testing.T) { | ||||||
| 	c.h_PRIVMSG(parseLine(":blah!moo@cows.com PRIVMSG #foo :test: prefix bar")) | 	c.h_PRIVMSG(parseLine(":blah!moo@cows.com PRIVMSG #foo :test: prefix bar")) | ||||||
| 	s.nc.Expect("PRIVMSG #foo :prefix bar") | 	s.nc.Expect("PRIVMSG #foo :prefix bar") | ||||||
| 
 | 
 | ||||||
| 	c.CommandStripPrefix = true | 	c.SimpleCommandStripPrefix = true | ||||||
| 	c.h_PRIVMSG(parseLine(":blah!moo@cows.com PRIVMSG #foo :prefix bar")) | 	c.h_PRIVMSG(parseLine(":blah!moo@cows.com PRIVMSG #foo :prefix bar")) | ||||||
| 	s.nc.Expect("PRIVMSG #foo :bar") | 	s.nc.Expect("PRIVMSG #foo :bar") | ||||||
| 	c.h_PRIVMSG(parseLine(":blah!moo@cows.com PRIVMSG #foo :test: prefix bar")) | 	c.h_PRIVMSG(parseLine(":blah!moo@cows.com PRIVMSG #foo :test: prefix bar")) | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue