Clean up BaseCommand interface. Make NickServ a Service.

This commit is contained in:
Jeremy Latt 2013-05-09 09:12:03 -07:00
parent 4b0cfa816c
commit 39f815df01
5 changed files with 79 additions and 77 deletions

View File

@ -27,11 +27,6 @@ type Client struct {
replies chan<- Reply
}
type ClientMessage interface {
Client() *Client
SetClient(*Client)
}
type ClientSet map[*Client]bool
func NewClient(server *Server, conn net.Conn) *Client {

View File

@ -14,17 +14,25 @@ type BaseCommand struct {
client *Client
}
func (base *BaseCommand) Client() *Client {
func (base BaseCommand) Client() *Client {
return base.client
}
func (base *BaseCommand) SetClient(c *Client) {
if base.client != nil {
panic("SetClient called twice!")
}
base.client = c
}
type EditableCommand interface {
Command
SetClient(*Client)
}
var (
ErrParseCommand = errors.New("failed to parse message")
parseCommandFuncs = map[string]func([]string) (Command, error){
parseCommandFuncs = map[string]func([]string) (EditableCommand, error){
"JOIN": NewJoinCommand,
"MODE": NewModeCommand,
"NICK": NewNickCommand,
@ -39,7 +47,7 @@ var (
}
)
func ParseCommand(line string) (Command, error) {
func ParseCommand(line string) (EditableCommand, error) {
command, args := parseLine(line)
constructor := parseCommandFuncs[command]
if constructor == nil {
@ -77,14 +85,14 @@ func parseLine(line string) (command string, args []string) {
// <command> [args...]
type UnknownCommand struct {
*BaseCommand
BaseCommand
command string
args []string
}
func NewUnknownCommand(command string, args []string) *UnknownCommand {
return &UnknownCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
command: command,
args: args,
}
@ -93,17 +101,17 @@ func NewUnknownCommand(command string, args []string) *UnknownCommand {
// PING <server1> [ <server2> ]
type PingCommand struct {
*BaseCommand
BaseCommand
server string
server2 string
}
func NewPingCommand(args []string) (Command, error) {
func NewPingCommand(args []string) (EditableCommand, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
msg := &PingCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
server: args[0],
}
if len(args) > 1 {
@ -115,17 +123,17 @@ func NewPingCommand(args []string) (Command, error) {
// PONG <server> [ <server2> ]
type PongCommand struct {
*BaseCommand
BaseCommand
server1 string
server2 string
}
func NewPongCommand(args []string) (Command, error) {
func NewPongCommand(args []string) (EditableCommand, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
message := &PongCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
server1: args[0],
}
if len(args) > 1 {
@ -137,16 +145,16 @@ func NewPongCommand(args []string) (Command, error) {
// PASS <password>
type PassCommand struct {
*BaseCommand
BaseCommand
password string
}
func NewPassCommand(args []string) (Command, error) {
func NewPassCommand(args []string) (EditableCommand, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
return &PassCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
password: args[0],
}, nil
}
@ -154,16 +162,16 @@ func NewPassCommand(args []string) (Command, error) {
// NICK <nickname>
type NickCommand struct {
*BaseCommand
BaseCommand
nickname string
}
func NewNickCommand(args []string) (Command, error) {
func NewNickCommand(args []string) (EditableCommand, error) {
if len(args) != 1 {
return nil, NotEnoughArgsError
}
return &NickCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
nickname: args[0],
}, nil
}
@ -171,19 +179,19 @@ func NewNickCommand(args []string) (Command, error) {
// USER <user> <mode> <unused> <realname>
type UserMsgCommand struct {
*BaseCommand
BaseCommand
user string
mode uint8
unused string
realname string
}
func NewUserMsgCommand(args []string) (Command, error) {
func NewUserMsgCommand(args []string) (EditableCommand, error) {
if len(args) != 4 {
return nil, NotEnoughArgsError
}
msg := &UserMsgCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
user: args[0],
unused: args[2],
realname: args[3],
@ -198,13 +206,13 @@ func NewUserMsgCommand(args []string) (Command, error) {
// QUIT [ <Quit Command> ]
type QuitCommand struct {
*BaseCommand
BaseCommand
message string
}
func NewQuitCommand(args []string) (Command, error) {
func NewQuitCommand(args []string) (EditableCommand, error) {
msg := &QuitCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
}
if len(args) > 0 {
msg.message = args[0]
@ -215,14 +223,14 @@ func NewQuitCommand(args []string) (Command, error) {
// JOIN ( <channel> *( "," <channel> ) [ <key> *( "," <key> ) ] ) / "0"
type JoinCommand struct {
*BaseCommand
BaseCommand
channels map[string]string
zero bool
}
func NewJoinCommand(args []string) (Command, error) {
func NewJoinCommand(args []string) (EditableCommand, error) {
msg := &JoinCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
channels: make(map[string]string),
}
@ -252,17 +260,17 @@ func NewJoinCommand(args []string) (Command, error) {
// PART <channel> *( "," <channel> ) [ <Part Command> ]
type PartCommand struct {
*BaseCommand
BaseCommand
channels []string
message string
}
func NewPartCommand(args []string) (Command, error) {
func NewPartCommand(args []string) (EditableCommand, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
msg := &PartCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
channels: strings.Split(args[0], ","),
}
if len(args) > 1 {
@ -274,17 +282,17 @@ func NewPartCommand(args []string) (Command, error) {
// PRIVMSG <target> <message>
type PrivMsgCommand struct {
*BaseCommand
BaseCommand
target string
message string
}
func NewPrivMsgCommand(args []string) (Command, error) {
func NewPrivMsgCommand(args []string) (EditableCommand, error) {
if len(args) < 2 {
return nil, NotEnoughArgsError
}
return &PrivMsgCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
target: args[0],
message: args[1],
}, nil
@ -301,17 +309,17 @@ func (m *PrivMsgCommand) TargetIsChannel() bool {
// TOPIC [newtopic]
type TopicCommand struct {
*BaseCommand
BaseCommand
channel string
topic string
}
func NewTopicCommand(args []string) (Command, error) {
func NewTopicCommand(args []string) (EditableCommand, error) {
if len(args) < 1 {
return nil, NotEnoughArgsError
}
msg := &TopicCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
channel: args[0],
}
if len(args) > 1 {
@ -321,18 +329,18 @@ func NewTopicCommand(args []string) (Command, error) {
}
type ModeCommand struct {
*BaseCommand
BaseCommand
nickname string
modes string
}
func NewModeCommand(args []string) (Command, error) {
func NewModeCommand(args []string) (EditableCommand, error) {
if len(args) == 0 {
return nil, NotEnoughArgsError
}
cmd := &ModeCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
nickname: args[0],
}

View File

@ -5,8 +5,9 @@ import (
)
type NickServCommand interface {
ClientMessage
HandleNickServ(*NickServ)
Client() *Client
SetClient(*Client)
}
type NickServ struct {
@ -14,11 +15,9 @@ type NickServ struct {
}
func NewNickServ(s *Server) *NickServ {
ns := &NickServ{}
ns.Service = NewService(s, "NickServ", func(m *PrivMsgCommand) {
m.HandleNickServ(ns)
})
return ns
return &NickServ{
Service: NewService(s, "NickServ"),
}
}
var (
@ -32,7 +31,7 @@ var (
// commands
//
func (m *PrivMsgCommand) HandleNickServ(ns *NickServ) {
func (ns *NickServ) HandleMsg(m *PrivMsgCommand) {
command, args := parseLine(m.message)
constructor := parseNickServCommandFuncs[command]
if constructor == nil {
@ -48,6 +47,7 @@ func (m *PrivMsgCommand) HandleNickServ(ns *NickServ) {
cmd.SetClient(m.Client())
log.Printf("%s %T %+v", ns.Id(), cmd, cmd)
cmd.HandleNickServ(ns)
}
@ -56,7 +56,7 @@ func (m *PrivMsgCommand) HandleNickServ(ns *NickServ) {
//
type RegisterCommand struct {
*BaseCommand
BaseCommand
password string
email string
}
@ -67,7 +67,7 @@ func NewRegisterCommand(args []string) (NickServCommand, error) {
}
cmd := &RegisterCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
password: args[0],
}
if len(args) > 1 {
@ -100,7 +100,7 @@ func (m *RegisterCommand) HandleNickServ(ns *NickServ) {
}
type IdentifyCommand struct {
*BaseCommand
BaseCommand
password string
}
@ -110,7 +110,7 @@ func NewIdentifyCommand(args []string) (NickServCommand, error) {
}
return &IdentifyCommand{
BaseCommand: &BaseCommand{},
BaseCommand: BaseCommand{},
password: args[0],
}, nil
}

View File

@ -13,8 +13,8 @@ type UserNameMap map[string]*User
type ServiceNameMap map[string]*Service
type Command interface {
ClientMessage
Handle(*Server)
Client() *Client
HandleServer(*Server)
}
type Server struct {
@ -47,7 +47,7 @@ func (server *Server) receiveCommands(commands <-chan Command) {
for command := range commands {
log.Printf("%s %T %+v", server.Id(), command, command)
command.Client().atime = time.Now()
command.Handle(server)
command.HandleServer(server)
}
}
@ -127,19 +127,19 @@ func (s *Server) DeleteChannel(channel *Channel) {
// commands
//
func (m *UnknownCommand) Handle(s *Server) {
func (m *UnknownCommand) HandleServer(s *Server) {
m.Client().replies <- ErrUnknownCommand(s, m.command)
}
func (m *PingCommand) Handle(s *Server) {
func (m *PingCommand) HandleServer(s *Server) {
m.Client().replies <- RplPong(s)
}
func (m *PongCommand) Handle(s *Server) {
func (m *PongCommand) HandleServer(s *Server) {
// no-op
}
func (m *PassCommand) Handle(s *Server) {
func (m *PassCommand) HandleServer(s *Server) {
err := bcrypt.CompareHashAndPassword(s.password, []byte(m.password))
if err != nil {
m.Client().replies <- ErrPasswdMismatch(s)
@ -150,7 +150,7 @@ func (m *PassCommand) Handle(s *Server) {
// no reply?
}
func (m *NickCommand) Handle(s *Server) {
func (m *NickCommand) HandleServer(s *Server) {
c := m.Client()
if c.user == nil {
c.replies <- RplNick(c, m.nickname)
@ -162,7 +162,7 @@ func (m *NickCommand) Handle(s *Server) {
c.user.replies <- ErrNoPrivileges(s)
}
func (m *UserMsgCommand) Handle(s *Server) {
func (m *UserMsgCommand) HandleServer(s *Server) {
c := m.Client()
if c.username != "" {
c.replies <- ErrAlreadyRegistered(s)
@ -173,7 +173,7 @@ func (m *UserMsgCommand) Handle(s *Server) {
s.tryRegister(c)
}
func (m *QuitCommand) Handle(s *Server) {
func (m *QuitCommand) HandleServer(s *Server) {
c := m.Client()
user := c.user
@ -191,7 +191,7 @@ func (m *QuitCommand) Handle(s *Server) {
user.LogoutClient(c)
if !user.HasClients() {
cmd := &PartCommand{
BaseCommand: &BaseCommand{c},
BaseCommand: BaseCommand{c},
}
for channel := range user.channels {
channel.commands <- cmd
@ -199,7 +199,7 @@ func (m *QuitCommand) Handle(s *Server) {
}
}
func (m *JoinCommand) Handle(s *Server) {
func (m *JoinCommand) HandleServer(s *Server) {
c := m.Client()
if c.user == nil {
@ -211,7 +211,7 @@ func (m *JoinCommand) Handle(s *Server) {
if m.zero {
cmd := &PartCommand{
BaseCommand: &BaseCommand{c},
BaseCommand: BaseCommand{c},
}
for channel := range c.user.channels {
channel.commands <- cmd
@ -224,7 +224,7 @@ func (m *JoinCommand) Handle(s *Server) {
}
}
func (m *PartCommand) Handle(s *Server) {
func (m *PartCommand) HandleServer(s *Server) {
user := m.Client().user
if user == nil {
@ -246,7 +246,7 @@ func (m *PartCommand) Handle(s *Server) {
}
}
func (m *TopicCommand) Handle(s *Server) {
func (m *TopicCommand) HandleServer(s *Server) {
user := m.Client().user
if user == nil {
@ -263,7 +263,7 @@ func (m *TopicCommand) Handle(s *Server) {
channel.commands <- m
}
func (m *PrivMsgCommand) Handle(s *Server) {
func (m *PrivMsgCommand) HandleServer(s *Server) {
service := s.services[m.target]
if service != nil {
service.commands <- m
@ -296,6 +296,6 @@ func (m *PrivMsgCommand) Handle(s *Server) {
target.commands <- m
}
func (m *ModeCommand) Handle(s *Server) {
func (m *ModeCommand) HandleServer(s *Server) {
m.Client().replies <- RplUModeIs(s, m.Client())
}

View File

@ -10,28 +10,27 @@ type ServiceCommand interface {
HandleService(*Service)
}
type PrivMsgCommandFunc func(*PrivMsgCommand)
type Service struct {
server *Server
name string
commands chan<- ServiceCommand
Handle PrivMsgCommandFunc
}
func NewService(s *Server, name string, Handle PrivMsgCommandFunc) *Service {
func NewService(s *Server, name string) *Service {
commands := make(chan ServiceCommand)
service := &Service{
server: s,
name: name,
commands: commands,
Handle: Handle,
}
go service.receiveCommands(commands)
s.services[name] = service
return service
}
func (service *Service) HandleMsg(m *PrivMsgCommand) {
}
func (service *Service) receiveCommands(commands <-chan ServiceCommand) {
for command := range commands {
log.Printf("%s %T %+V", service.Id(), command, command)
@ -60,5 +59,5 @@ func (service *Service) Reply(client *Client, message string) {
//
func (m *PrivMsgCommand) HandleService(s *Service) {
s.Handle(m)
s.HandleMsg(m)
}