From 2ff93d74be3bf3d24cbe6a7d11aad76d73f6a015 Mon Sep 17 00:00:00 2001 From: Jeremy Latt Date: Sat, 11 May 2013 13:55:01 -0700 Subject: [PATCH] Make NickServ actually work. --- src/irc/client.go | 14 ++++++++++--- src/irc/commands.go | 40 +++++++++++++++++++++++++++++++----- src/irc/nickserv.go | 25 ++++++++++++++++------- src/irc/reply.go | 2 +- src/irc/server.go | 12 +++++++---- src/irc/service.go | 50 +++++++++++++++++++++++++++------------------ 6 files changed, 103 insertions(+), 40 deletions(-) diff --git a/src/irc/client.go b/src/irc/client.go index f507c205..14650312 100644 --- a/src/irc/client.go +++ b/src/irc/client.go @@ -44,11 +44,15 @@ func NewClient(server *Server, conn net.Conn) *Client { func (c *Client) readConn(recv <-chan string) { for str := range recv { - log.Printf("%s > %s", c.Id(), str) + log.Printf("%s → %s", c.conn.RemoteAddr(), str) m, err := ParseCommand(str) if err != nil { - c.Replies() <- ErrNeedMoreParams(c.server, str) + if err == NotEnoughArgsError { + c.Replies() <- ErrNeedMoreParams(c.server, str) + } else { + c.Replies() <- ErrUnknownCommand(c.server, str) + } continue } @@ -60,7 +64,7 @@ func (c *Client) readConn(recv <-chan string) { func (c *Client) writeConn(write chan<- string, replies <-chan Reply) { for reply := range replies { replyStr := reply.String(c) - log.Printf("%s < %s", c.Id(), replyStr) + log.Printf("%s ← %s", c.conn.RemoteAddr(), replyStr) write <- replyStr } } @@ -112,6 +116,10 @@ func (c Client) Id() string { return c.UserHost() } +func (c Client) String() string { + return c.Id() +} + func (c Client) PublicId() string { return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Nick(), c.server.Id()) } diff --git a/src/irc/commands.go b/src/irc/commands.go index 27c4dd91..71b3da12 100644 --- a/src/irc/commands.go +++ b/src/irc/commands.go @@ -2,6 +2,7 @@ package irc import ( "errors" + "fmt" "strconv" "strings" ) @@ -38,15 +39,15 @@ type BaseCommand struct { client *Client } -func (base BaseCommand) Client() *Client { - return base.client +func (command BaseCommand) Client() *Client { + return command.client } -func (base *BaseCommand) SetClient(c *Client) { - if base.client != nil { +func (command *BaseCommand) SetClient(c *Client) { + if command.client != nil { panic("SetClient called twice!") } - base.client = c + command.client = c } func ParseCommand(line string) (EditableCommand, error) { @@ -108,6 +109,10 @@ type PingCommand struct { server2 string } +func (cmd PingCommand) String() string { + return fmt.Sprintf("PING(server=%s, server2=%s)", cmd.server, cmd.server2) +} + func NewPingCommand(args []string) (EditableCommand, error) { if len(args) < 1 { return nil, NotEnoughArgsError @@ -130,6 +135,10 @@ type PongCommand struct { server2 string } +func (cmd PongCommand) String() string { + return fmt.Sprintf("PONG(server1=%s, server2=%s)", cmd.server1, cmd.server2) +} + func NewPongCommand(args []string) (EditableCommand, error) { if len(args) < 1 { return nil, NotEnoughArgsError @@ -168,6 +177,10 @@ type NickCommand struct { nickname string } +func (m NickCommand) String() string { + return fmt.Sprintf("NICK(nickname=%s)", m.nickname) +} + func NewNickCommand(args []string) (EditableCommand, error) { if len(args) != 1 { return nil, NotEnoughArgsError @@ -188,6 +201,11 @@ type UserMsgCommand struct { realname string } +func (cmd UserMsgCommand) String() string { + return fmt.Sprintf("USER(user=%s, mode=%o, unused=%s, realname=%s)", + cmd.user, cmd.mode, cmd.unused, cmd.realname) +} + func NewUserMsgCommand(args []string) (EditableCommand, error) { if len(args) != 4 { return nil, NotEnoughArgsError @@ -212,6 +230,10 @@ type QuitCommand struct { message string } +func (cmd QuitCommand) String() string { + return fmt.Sprintf("QUIT(message=%s)", cmd.message) +} + func NewQuitCommand(args []string) (EditableCommand, error) { msg := &QuitCommand{ BaseCommand: BaseCommand{}, @@ -289,6 +311,10 @@ type PrivMsgCommand struct { message string } +func (cmd PrivMsgCommand) String() string { + return fmt.Sprintf("PRIVMSG(target=%s, message=%s)", cmd.target, cmd.message) +} + func NewPrivMsgCommand(args []string) (EditableCommand, error) { if len(args) < 2 { return nil, NotEnoughArgsError @@ -336,6 +362,10 @@ type ModeCommand struct { modes string } +func (cmd ModeCommand) String() string { + return fmt.Sprintf("MODE(nickname=%s, modes=%s)", cmd.nickname, cmd.modes) +} + func NewModeCommand(args []string) (EditableCommand, error) { if len(args) == 0 { return nil, NotEnoughArgsError diff --git a/src/irc/nickserv.go b/src/irc/nickserv.go index c86bae75..eb9007c9 100644 --- a/src/irc/nickserv.go +++ b/src/irc/nickserv.go @@ -1,6 +1,7 @@ package irc import ( + "fmt" "log" ) @@ -11,13 +12,15 @@ type NickServCommand interface { } type NickServ struct { - *Service + BaseService } -func NewNickServ(s *Server) *NickServ { - return &NickServ{ - Service: NewService(s, "NickServ"), - } +func NewNickServ(s *Server) Service { + return NewService(new(NickServ), s, "NickServ") +} + +func (ns *NickServ) SetBase(base *BaseService) { + ns.BaseService = *base } var ( @@ -31,7 +34,7 @@ var ( // commands // -func (ns *NickServ) HandleMsg(m *PrivMsgCommand) { +func (ns *NickServ) HandlePrivMsg(m *PrivMsgCommand) { command, args := parseLine(m.message) constructor := parseNickServCommandFuncs[command] if constructor == nil { @@ -46,7 +49,7 @@ func (ns *NickServ) HandleMsg(m *PrivMsgCommand) { } cmd.SetClient(m.Client()) - log.Printf("%s %T %+v", ns.Id(), cmd, cmd) + log.Printf("%s ← %s", ns, cmd) cmd.HandleNickServ(ns) } @@ -61,6 +64,10 @@ type RegisterCommand struct { email string } +func (m RegisterCommand) String() string { + return fmt.Sprintf("REGISTER(email=%s, password=%s)", m.email, m.password) +} + func NewRegisterCommand(args []string) (NickServCommand, error) { if len(args) == 0 { return nil, NotEnoughArgsError @@ -104,6 +111,10 @@ type IdentifyCommand struct { password string } +func (m IdentifyCommand) String() string { + return fmt.Sprintf("IDENTIFY(password=%s)", m.password) +} + func NewIdentifyCommand(args []string) (NickServCommand, error) { if len(args) == 0 { return nil, NotEnoughArgsError diff --git a/src/irc/reply.go b/src/irc/reply.go index db09493b..ec5c42b9 100644 --- a/src/irc/reply.go +++ b/src/irc/reply.go @@ -100,7 +100,7 @@ func RplWelcome(source Identifier, client *Client) Reply { func RplYourHost(server *Server, target *Client) Reply { return NewNumericReply(server, RPL_YOURHOST, - "Your host is %s, running version %s", server.hostname, VERSION) + "Your host is %s, running version %s", server.name, VERSION) } func RplCreated(server *Server) Reply { diff --git a/src/irc/server.go b/src/irc/server.go index e99d28b1..2cedab3b 100644 --- a/src/irc/server.go +++ b/src/irc/server.go @@ -10,7 +10,7 @@ import ( type ClientNameMap map[string]*Client type ChannelNameMap map[string]*Channel type UserNameMap map[string]*User -type ServiceNameMap map[string]*Service +type ServiceNameMap map[string]Service type Server struct { hostname string @@ -40,7 +40,7 @@ func NewServer(name string) *Server { func (server *Server) receiveCommands(commands <-chan Command) { for command := range commands { - log.Printf("%s %T %+v", server.Id(), command, command) + log.Printf("%s ← %s %s", server, command.Client(), command) command.Client().atime = time.Now() command.HandleServer(server) } @@ -103,7 +103,11 @@ func (s *Server) tryRegister(c *Client) { } func (s Server) Id() string { - return s.hostname + return s.name +} + +func (s Server) String() string { + return s.Id() } func (s Server) PublicId() string { @@ -122,7 +126,7 @@ func (s *Server) DeleteChannel(channel *Channel) { // commands // -func (m *UnknownCommand) HandleServer(s *Server) { +func (m UnknownCommand) HandleServer(s *Server) { m.Client().Replies() <- ErrUnknownCommand(s, m.command) } diff --git a/src/irc/service.go b/src/irc/service.go index 49e1af13..b13a20c9 100644 --- a/src/irc/service.go +++ b/src/irc/service.go @@ -7,60 +7,70 @@ import ( type ServiceCommand interface { Command - HandleService(*Service) + HandleService(Service) } -type Service struct { +type Service interface { + Identifier + Commands() chan<- ServiceCommand + HandlePrivMsg(*PrivMsgCommand) +} + +type EditableService interface { + Service + SetBase(*BaseService) +} + +type BaseService struct { server *Server name string commands chan<- ServiceCommand } -func NewService(s *Server, name string) *Service { +func NewService(service EditableService, s *Server, name string) Service { commands := make(chan ServiceCommand) - service := &Service{ + base := &BaseService{ server: s, name: name, commands: commands, } - go service.receiveCommands(commands) + go receiveCommands(service, commands) + service.SetBase(base) s.services[name] = service return service } -func (service *Service) HandleMsg(m *PrivMsgCommand) {} - -func (service *Service) receiveCommands(commands <-chan ServiceCommand) { +func receiveCommands(service Service, commands <-chan ServiceCommand) { for command := range commands { - log.Printf("%s %T %+V", service.Id(), command, command) + log.Printf("%s ← %s %s", service.Id(), command.Client(), command) command.HandleService(service) } } -func (service Service) Id() string { +func (service BaseService) Id() string { return fmt.Sprintf("%s!%s@%s", service.name, service.name, service.server.name) } -func (service Service) PublicId() string { +func (service BaseService) String() string { return service.Id() } -func (service Service) Nick() string { +func (service BaseService) PublicId() string { + return service.Id() +} + +func (service BaseService) Nick() string { return service.name } -func (service *Service) Reply(client *Client, message string) { +func (service *BaseService) Reply(client *Client, message string) { client.Replies() <- RplPrivMsg(service, client, message) } -func (service Service) Commands() chan<- ServiceCommand { +func (service BaseService) Commands() chan<- ServiceCommand { return service.commands } -// -// commands -// - -func (m *PrivMsgCommand) HandleService(s *Service) { - s.HandleMsg(m) +func (m *PrivMsgCommand) HandleService(service Service) { + service.HandlePrivMsg(m) }