3
0
mirror of https://github.com/ergochat/ergo.git synced 2025-02-18 06:30:39 +01:00

Update a bunch of messages and fix reply struct embedding.

This commit is contained in:
Jeremy Latt 2013-05-11 18:28:18 -07:00
parent 8e5ff51257
commit c42cd92f91
9 changed files with 292 additions and 218 deletions

View File

@ -4,6 +4,10 @@ import (
"log" "log"
) )
const (
DEBUG_CHANNEL = true
)
type Channel struct { type Channel struct {
server *Server server *Server
commands chan<- ChannelCommand commands chan<- ChannelCommand
@ -51,6 +55,9 @@ func NewChannel(s *Server, name string) *Channel {
// Forward `Reply`s to all `User`s of the `Channel`. // Forward `Reply`s to all `User`s of the `Channel`.
func (ch *Channel) receiveReplies(replies <-chan Reply) { func (ch *Channel) receiveReplies(replies <-chan Reply) {
for reply := range replies { for reply := range replies {
if DEBUG_CHANNEL {
log.Printf("%s → %s", ch, reply)
}
for user := range ch.members { for user := range ch.members {
if user != reply.Source() { if user != reply.Source() {
user.replies <- reply user.replies <- reply
@ -61,7 +68,9 @@ func (ch *Channel) receiveReplies(replies <-chan Reply) {
func (ch *Channel) receiveCommands(commands <-chan ChannelCommand) { func (ch *Channel) receiveCommands(commands <-chan ChannelCommand) {
for command := range commands { for command := range commands {
log.Printf("%s %T %+v", ch.Id(), command, command) if DEBUG_CHANNEL {
log.Printf("%s ← %s %s", ch, command.Source(), command)
}
command.HandleChannel(ch) command.HandleChannel(ch)
} }
} }
@ -89,18 +98,26 @@ func (channel *Channel) GetTopic(replier Replier) {
replier.Replies() <- RplTopic(channel) replier.Replies() <- RplTopic(channel)
} }
func (channel Channel) Id() string { func (channel *Channel) Id() string {
return channel.name return channel.name
} }
func (channel Channel) PublicId() string { func (channel *Channel) PublicId() string {
return channel.name return channel.name
} }
func (channel Channel) Commands() chan<- ChannelCommand { func (channel *Channel) Commands() chan<- ChannelCommand {
return channel.commands return channel.commands
} }
func (channel *Channel) Replies() chan<- Reply {
return channel.replies
}
func (channel *Channel) String() string {
return channel.Id()
}
// //
// commands // commands
// //
@ -170,5 +187,5 @@ func (m *TopicCommand) HandleChannel(channel *Channel) {
} }
func (m *PrivMsgCommand) HandleChannel(channel *Channel) { func (m *PrivMsgCommand) HandleChannel(channel *Channel) {
channel.replies <- RplPrivMsgChannel(channel, m.Client().user, m.message) channel.Replies() <- RplPrivMsgChannel(channel, m.Client().user, m.message)
} }

View File

@ -35,7 +35,7 @@ func NewClient(server *Server, conn net.Conn) *Client {
client := &Client{ client := &Client{
conn: conn, conn: conn,
hostname: LookupHostname(conn.RemoteAddr()), hostname: conn.RemoteAddr().String(),
server: server, server: server,
replies: replies, replies: replies,
} }
@ -73,57 +73,57 @@ func (c *Client) writeConn(write chan<- string, replies <-chan Reply) {
} }
} }
func (c Client) Replies() chan<- Reply { func (c *Client) Replies() chan<- Reply {
return c.replies return c.replies
} }
func (c Client) Server() *Server { func (c *Client) Server() *Server {
return c.server return c.server
} }
func (c Client) Nick() string { func (c *Client) Nick() string {
if c.user != nil { if c.user != nil {
return c.user.nick return c.user.Nick()
} }
if c.nick != "" { if c.nick != "" {
return c.nick return c.nick
} }
return "*" return "guest"
} }
func (c Client) UModeString() string { func (c *Client) UModeString() string {
return "" return ""
} }
func (c Client) HasNick() bool { func (c *Client) HasNick() bool {
return c.nick != "" return c.Nick() != ""
} }
func (c Client) HasUser() bool { func (c *Client) HasUsername() bool {
return c.username != "" return c.username != ""
} }
func (c Client) Username() string { func (c *Client) Username() string {
if c.HasUser() { if c.HasUsername() {
return c.username return c.username
} }
return "*" return "guest"
} }
func (c Client) UserHost() string { func (c *Client) UserHost() string {
return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Username(), c.hostname) return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Username(), c.hostname)
} }
func (c Client) Id() string { func (c *Client) Id() string {
return c.UserHost() return c.UserHost()
} }
func (c Client) String() string { func (c *Client) String() string {
return c.Id() return c.hostname
} }
func (c Client) PublicId() string { func (c *Client) PublicId() string {
return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Nick(), c.server.Id()) return fmt.Sprintf("%s!%s@%s", c.Nick(), c.Nick(), c.server.Id())
} }

View File

@ -9,6 +9,7 @@ import (
type Command interface { type Command interface {
Client() *Client Client() *Client
Source() Identifier
HandleServer(*Server) HandleServer(*Server)
} }
@ -39,7 +40,7 @@ type BaseCommand struct {
client *Client client *Client
} }
func (command BaseCommand) Client() *Client { func (command *BaseCommand) Client() *Client {
return command.client return command.client
} }
@ -50,6 +51,17 @@ func (command *BaseCommand) SetClient(c *Client) {
command.client = c command.client = c
} }
func (command *BaseCommand) Source() Identifier {
client := command.Client()
if client == nil {
return nil
}
if client.user != nil {
return client.user
}
return client
}
func ParseCommand(line string) (EditableCommand, error) { func ParseCommand(line string) (EditableCommand, error) {
command, args := parseLine(line) command, args := parseLine(line)
constructor := parseCommandFuncs[command] constructor := parseCommandFuncs[command]
@ -93,6 +105,10 @@ type UnknownCommand struct {
args []string args []string
} }
func (cmd *UnknownCommand) String() string {
return fmt.Sprintf("UNKNOWN(command=%s, args=%s)", cmd.command, cmd.args)
}
func NewUnknownCommand(command string, args []string) *UnknownCommand { func NewUnknownCommand(command string, args []string) *UnknownCommand {
return &UnknownCommand{ return &UnknownCommand{
BaseCommand: BaseCommand{}, BaseCommand: BaseCommand{},
@ -109,7 +125,7 @@ type PingCommand struct {
server2 string server2 string
} }
func (cmd PingCommand) String() string { func (cmd *PingCommand) String() string {
return fmt.Sprintf("PING(server=%s, server2=%s)", cmd.server, cmd.server2) return fmt.Sprintf("PING(server=%s, server2=%s)", cmd.server, cmd.server2)
} }
@ -135,7 +151,7 @@ type PongCommand struct {
server2 string server2 string
} }
func (cmd PongCommand) String() string { func (cmd *PongCommand) String() string {
return fmt.Sprintf("PONG(server1=%s, server2=%s)", cmd.server1, cmd.server2) return fmt.Sprintf("PONG(server1=%s, server2=%s)", cmd.server1, cmd.server2)
} }
@ -160,6 +176,10 @@ type PassCommand struct {
password string password string
} }
func (cmd *PassCommand) String() string {
return fmt.Sprintf("PASS(password=%s)", cmd.password)
}
func NewPassCommand(args []string) (EditableCommand, error) { func NewPassCommand(args []string) (EditableCommand, error) {
if len(args) < 1 { if len(args) < 1 {
return nil, NotEnoughArgsError return nil, NotEnoughArgsError
@ -177,7 +197,7 @@ type NickCommand struct {
nickname string nickname string
} }
func (m NickCommand) String() string { func (m *NickCommand) String() string {
return fmt.Sprintf("NICK(nickname=%s)", m.nickname) return fmt.Sprintf("NICK(nickname=%s)", m.nickname)
} }
@ -201,7 +221,7 @@ type UserMsgCommand struct {
realname string realname string
} }
func (cmd UserMsgCommand) String() string { func (cmd *UserMsgCommand) String() string {
return fmt.Sprintf("USER(user=%s, mode=%o, unused=%s, realname=%s)", return fmt.Sprintf("USER(user=%s, mode=%o, unused=%s, realname=%s)",
cmd.user, cmd.mode, cmd.unused, cmd.realname) cmd.user, cmd.mode, cmd.unused, cmd.realname)
} }
@ -230,7 +250,7 @@ type QuitCommand struct {
message string message string
} }
func (cmd QuitCommand) String() string { func (cmd *QuitCommand) String() string {
return fmt.Sprintf("QUIT(message=%s)", cmd.message) return fmt.Sprintf("QUIT(message=%s)", cmd.message)
} }
@ -252,6 +272,10 @@ type JoinCommand struct {
zero bool zero bool
} }
func (cmd *JoinCommand) String() string {
return fmt.Sprintf("JOIN(channels=%s, zero=%t)", cmd.channels, cmd.zero)
}
func NewJoinCommand(args []string) (EditableCommand, error) { func NewJoinCommand(args []string) (EditableCommand, error) {
msg := &JoinCommand{ msg := &JoinCommand{
BaseCommand: BaseCommand{}, BaseCommand: BaseCommand{},
@ -289,6 +313,10 @@ type PartCommand struct {
message string message string
} }
func (cmd *PartCommand) String() string {
return fmt.Sprintf("PART(channels=%s, message=%s)", cmd.channels, cmd.message)
}
func NewPartCommand(args []string) (EditableCommand, error) { func NewPartCommand(args []string) (EditableCommand, error) {
if len(args) < 1 { if len(args) < 1 {
return nil, NotEnoughArgsError return nil, NotEnoughArgsError
@ -311,7 +339,7 @@ type PrivMsgCommand struct {
message string message string
} }
func (cmd PrivMsgCommand) String() string { func (cmd *PrivMsgCommand) String() string {
return fmt.Sprintf("PRIVMSG(target=%s, message=%s)", cmd.target, cmd.message) return fmt.Sprintf("PRIVMSG(target=%s, message=%s)", cmd.target, cmd.message)
} }
@ -342,6 +370,10 @@ type TopicCommand struct {
topic string topic string
} }
func (cmd *TopicCommand) String() string {
return fmt.Sprintf("TOPIC(channel=%s, topic=%s)", cmd.channel, cmd.topic)
}
func NewTopicCommand(args []string) (EditableCommand, error) { func NewTopicCommand(args []string) (EditableCommand, error) {
if len(args) < 1 { if len(args) < 1 {
return nil, NotEnoughArgsError return nil, NotEnoughArgsError
@ -362,7 +394,7 @@ type ModeCommand struct {
modes string modes string
} }
func (cmd ModeCommand) String() string { func (cmd *ModeCommand) String() string {
return fmt.Sprintf("MODE(nickname=%s, modes=%s)", cmd.nickname, cmd.modes) return fmt.Sprintf("MODE(nickname=%s, modes=%s)", cmd.nickname, cmd.modes)
} }

View File

@ -6,142 +6,142 @@ const (
const ( const (
// numeric codes // numeric codes
RPL_WELCOME = "001" RPL_WELCOME = 1
RPL_YOURHOST = "002" RPL_YOURHOST = 2
RPL_CREATED = "003" RPL_CREATED = 3
RPL_MYINFO = "004" RPL_MYINFO = 4
RPL_BOUNCE = "005" RPL_BOUNCE = 5
RPL_TRACELINK = "200" RPL_TRACELINK = 200
RPL_TRACECONNECTING = "201" RPL_TRACECONNECTING = 201
RPL_TRACEHANDSHAKE = "202" RPL_TRACEHANDSHAKE = 202
RPL_TRACEUNKNOWN = "203" RPL_TRACEUNKNOWN = 203
RPL_TRACEOPERATOR = "204" RPL_TRACEOPERATOR = 204
RPL_TRACEUSER = "205" RPL_TRACEUSER = 205
RPL_TRACESERVER = "206" RPL_TRACESERVER = 206
RPL_TRACESERVICE = "207" RPL_TRACESERVICE = 207
RPL_TRACENEWTYPE = "208" RPL_TRACENEWTYPE = 208
RPL_TRACECLASS = "209" RPL_TRACECLASS = 209
RPL_TRACERECONNECT = "210" RPL_TRACERECONNECT = 210
RPL_STATSLINKINFO = "211" RPL_STATSLINKINFO = 211
RPL_STATSCOMMANDS = "212" RPL_STATSCOMMANDS = 212
RPL_ENDOFSTATS = "219" RPL_ENDOFSTATS = 219
RPL_UMODEIS = "221" RPL_UMODEIS = 221
RPL_SERVLIST = "234" RPL_SERVLIST = 234
RPL_SERVLISTEND = "235" RPL_SERVLISTEND = 235
RPL_STATSUPTIME = "242" RPL_STATSUPTIME = 242
RPL_STATSOLINE = "243" RPL_STATSOLINE = 243
RPL_LUSERCLIENT = "251" RPL_LUSERCLIENT = 251
RPL_LUSEROP = "252" RPL_LUSEROP = 252
RPL_LUSERUNKNOWN = "253" RPL_LUSERUNKNOWN = 253
RPL_LUSERCHANNELS = "254" RPL_LUSERCHANNELS = 254
RPL_LUSERME = "255" RPL_LUSERME = 255
RPL_ADMINME = "256" RPL_ADMINME = 256
RPL_ADMINLOC1 = "257" RPL_ADMINLOC1 = 257
RPL_ADMINLOC2 = "258" RPL_ADMINLOC2 = 258
RPL_ADMINEMAIL = "259" RPL_ADMINEMAIL = 259
RPL_TRACELOG = "261" RPL_TRACELOG = 261
RPL_TRACEEND = "262" RPL_TRACEEND = 262
RPL_TRYAGAIN = "263" RPL_TRYAGAIN = 263
RPL_AWAY = "301" RPL_AWAY = 301
RPL_USERHOST = "302" RPL_USERHOST = 302
RPL_ISON = "303" RPL_ISON = 303
RPL_UNAWAY = "305" RPL_UNAWAY = 305
RPL_NOWAWAY = "306" RPL_NOWAWAY = 306
RPL_WHOISUSER = "311" RPL_WHOISUSER = 311
RPL_WHOISSERVER = "312" RPL_WHOISSERVER = 312
RPL_WHOISOPERATOR = "313" RPL_WHOISOPERATOR = 313
RPL_WHOWASUSER = "314" RPL_WHOWASUSER = 314
RPL_ENDOFWHO = "315" RPL_ENDOFWHO = 315
RPL_WHOISIDLE = "317" RPL_WHOISIDLE = 317
RPL_ENDOFWHOIS = "318" RPL_ENDOFWHOIS = 318
RPL_WHOISCHANNELS = "319" RPL_WHOISCHANNELS = 319
RPL_LIST = "322" RPL_LIST = 322
RPL_LISTEND = "323" RPL_LISTEND = 323
RPL_CHANNELMODEIS = "324" RPL_CHANNELMODEIS = 324
RPL_UNIQOPIS = "325" RPL_UNIQOPIS = 325
RPL_NOTOPIC = "331" RPL_NOTOPIC = 331
RPL_TOPIC = "332" RPL_TOPIC = 332
RPL_INVITING = "341" RPL_INVITING = 341
RPL_SUMMONING = "342" RPL_SUMMONING = 342
RPL_INVITELIST = "346" RPL_INVITELIST = 346
RPL_ENDOFINVITELIST = "347" RPL_ENDOFINVITELIST = 347
RPL_EXCEPTLIST = "348" RPL_EXCEPTLIST = 348
RPL_ENDOFEXCEPTLIST = "349" RPL_ENDOFEXCEPTLIST = 349
RPL_VERSION = "351" RPL_VERSION = 351
RPL_WHOREPLY = "352" RPL_WHOREPLY = 352
RPL_NAMREPLY = "353" RPL_NAMREPLY = 353
RPL_LINKS = "364" RPL_LINKS = 364
RPL_ENDOFLINKS = "365" RPL_ENDOFLINKS = 365
RPL_ENDOFNAMES = "366" RPL_ENDOFNAMES = 366
RPL_BANLIST = "367" RPL_BANLIST = 367
RPL_ENDOFBANLIST = "368" RPL_ENDOFBANLIST = 368
RPL_ENDOFWHOWAS = "369" RPL_ENDOFWHOWAS = 369
RPL_INFO = "371" RPL_INFO = 371
RPL_MOTD = "372" RPL_MOTD = 372
RPL_ENDOFINFO = "374" RPL_ENDOFINFO = 374
RPL_MOTDSTART = "375" RPL_MOTDSTART = 375
RPL_ENDOFMOTD = "376" RPL_ENDOFMOTD = 376
RPL_YOUREOPER = "381" RPL_YOUREOPER = 381
RPL_REHASHING = "382" RPL_REHASHING = 382
RPL_YOURESERVICE = "383" RPL_YOURESERVICE = 383
RPL_TIME = "391" RPL_TIME = 391
RPL_USERSSTART = "392" RPL_USERSSTART = 392
RPL_USERS = "393" RPL_USERS = 393
RPL_ENDOFUSERS = "394" RPL_ENDOFUSERS = 394
RPL_NOUSERS = "395" RPL_NOUSERS = 395
ERR_NOSUCHNICK = "401" ERR_NOSUCHNICK = 401
ERR_NOSUCHSERVER = "402" ERR_NOSUCHSERVER = 402
ERR_NOSUCHCHANNEL = "403" ERR_NOSUCHCHANNEL = 403
ERR_CANNOTSENDTOCHAN = "404" ERR_CANNOTSENDTOCHAN = 404
ERR_TOOMANYCHANNELS = "405" ERR_TOOMANYCHANNELS = 405
ERR_WASNOSUCHNICK = "406" ERR_WASNOSUCHNICK = 406
ERR_TOOMANYTARGETS = "407" ERR_TOOMANYTARGETS = 407
ERR_NOSUCHSERVICE = "408" ERR_NOSUCHSERVICE = 408
ERR_NOORIGIN = "409" ERR_NOORIGIN = 409
ERR_NORECIPIENT = "411" ERR_NORECIPIENT = 411
ERR_NOTEXTTOSEND = "412" ERR_NOTEXTTOSEND = 412
ERR_NOTOPLEVEL = "413" ERR_NOTOPLEVEL = 413
ERR_WILDTOPLEVEL = "414" ERR_WILDTOPLEVEL = 414
ERR_BADMASK = "415" ERR_BADMASK = 415
ERR_UNKNOWNCOMMAND = "421" ERR_UNKNOWNCOMMAND = 421
ERR_NOMOTD = "422" ERR_NOMOTD = 422
ERR_NOADMININFO = "423" ERR_NOADMININFO = 423
ERR_FILEERROR = "424" ERR_FILEERROR = 424
ERR_NONICKNAMEGIVEN = "431" ERR_NONICKNAMEGIVEN = 431
ERR_ERRONEUSNICKNAME = "432" ERR_ERRONEUSNICKNAME = 432
ERR_NICKNAMEINUSE = "433" ERR_NICKNAMEINUSE = 433
ERR_NICKCOLLISION = "436" ERR_NICKCOLLISION = 436
ERR_UNAVAILRESOURCE = "437" ERR_UNAVAILRESOURCE = 437
ERR_USERNOTINCHANNEL = "441" ERR_USERNOTINCHANNEL = 441
ERR_NOTONCHANNEL = "442" ERR_NOTONCHANNEL = 442
ERR_USERONCHANNEL = "443" ERR_USERONCHANNEL = 443
ERR_NOLOGIN = "444" ERR_NOLOGIN = 444
ERR_SUMMONDISABLED = "445" ERR_SUMMONDISABLED = 445
ERR_USERSDISABLED = "446" ERR_USERSDISABLED = 446
ERR_NOTREGISTERED = "451" ERR_NOTREGISTERED = 451
ERR_NEEDMOREPARAMS = "461" ERR_NEEDMOREPARAMS = 461
ERR_ALREADYREGISTRED = "462" ERR_ALREADYREGISTRED = 462
ERR_NOPERMFORHOST = "463" ERR_NOPERMFORHOST = 463
ERR_PASSWDMISMATCH = "464" ERR_PASSWDMISMATCH = 464
ERR_YOUREBANNEDCREEP = "465" ERR_YOUREBANNEDCREEP = 465
ERR_YOUWILLBEBANNED = "466" ERR_YOUWILLBEBANNED = 466
ERR_KEYSET = "467" ERR_KEYSET = 467
ERR_CHANNELISFULL = "471" ERR_CHANNELISFULL = 471
ERR_UNKNOWNMODE = "472" ERR_UNKNOWNMODE = 472
ERR_INVITEONLYCHAN = "473" ERR_INVITEONLYCHAN = 473
ERR_BANNEDFROMCHAN = "474" ERR_BANNEDFROMCHAN = 474
ERR_BADCHANNELKEY = "475" ERR_BADCHANNELKEY = 475
ERR_BADCHANMASK = "476" ERR_BADCHANMASK = 476
ERR_NOCHANMODES = "477" ERR_NOCHANMODES = 477
ERR_BANLISTFULL = "478" ERR_BANLISTFULL = 478
ERR_NOPRIVILEGES = "481" ERR_NOPRIVILEGES = 481
ERR_CHANOPRIVSNEEDED = "482" ERR_CHANOPRIVSNEEDED = 482
ERR_CANTKILLSERVER = "483" ERR_CANTKILLSERVER = 483
ERR_RESTRICTED = "484" ERR_RESTRICTED = 484
ERR_UNIQOPPRIVSNEEDED = "485" ERR_UNIQOPPRIVSNEEDED = 485
ERR_NOOPERHOST = "491" ERR_NOOPERHOST = 491
ERR_UMODEUNKNOWNFLAG = "501" ERR_UMODEUNKNOWNFLAG = 501
ERR_USERSDONTMATCH = "502" ERR_USERSDONTMATCH = 502
// message codes // message codes
RPL_INVITE = "INVITE" RPL_INVITE = "INVITE"
RPL_JOIN = "JOIN" RPL_JOIN = "JOIN"

View File

@ -74,7 +74,7 @@ type RegisterCommand struct {
email string email string
} }
func (m RegisterCommand) String() string { func (m *RegisterCommand) String() string {
return fmt.Sprintf("REGISTER(email=%s, password=%s)", m.email, m.password) return fmt.Sprintf("REGISTER(email=%s, password=%s)", m.email, m.password)
} }
@ -107,11 +107,11 @@ func (m *RegisterCommand) HandleNickServ(ns *NickServ) {
} }
user := NewUser(client.nick, m.password, ns.server) user := NewUser(client.nick, m.password, ns.server)
ns.server.users[client.nick] = user
ns.Reply(client, "You have registered.") ns.Reply(client, "You have registered.")
if !user.Login(client, client.nick, m.password) { if !user.Login(client, client.nick, m.password) {
ns.Reply(client, "Login failed.") ns.Reply(client, "Login failed.")
return
} }
ns.Reply(client, "Logged in.") ns.Reply(client, "Logged in.")
} }
@ -121,7 +121,7 @@ type IdentifyCommand struct {
password string password string
} }
func (m IdentifyCommand) String() string { func (m *IdentifyCommand) String() string {
return fmt.Sprintf("IDENTIFY(password=%s)", m.password) return fmt.Sprintf("IDENTIFY(password=%s)", m.password)
} }

View File

@ -22,78 +22,88 @@ type Reply interface {
Source() Identifier Source() Identifier
} }
type BasicReply struct { type BaseReply struct {
source Identifier source Identifier
code string
message string message string
} }
func NewBasicReply(source Identifier, code string, func (reply *BaseReply) Source() Identifier {
format string, args ...interface{}) *BasicReply { return reply.source
message := fmt.Sprintf(format, args...)
fullMessage := fmt.Sprintf(":%s %s %s", source.Id(), code, message)
return &BasicReply{source, code, fullMessage}
} }
func (reply BasicReply) String() string { type StringReply struct {
BaseReply
code string
}
func NewStringReply(source Identifier, code string,
format string, args ...interface{}) *StringReply {
message := fmt.Sprintf(format, args...)
fullMessage := fmt.Sprintf(":%s %s %s", source.Id(), code, message)
return &StringReply{BaseReply{source, fullMessage}, code}
}
func (reply *StringReply) Format(client *Client) string {
return reply.message
}
func (reply *StringReply) String() string {
return fmt.Sprintf("Reply(source=%s, code=%s, message=%s)", return fmt.Sprintf("Reply(source=%s, code=%s, message=%s)",
reply.source, reply.code, reply.message) reply.source, reply.code, reply.message)
} }
func (reply BasicReply) Format(client *Client) string {
return reply.message
}
func (reply BasicReply) Source() Identifier {
return reply.source
}
type NumericReply struct { type NumericReply struct {
BasicReply BaseReply
code int
} }
func NewNumericReply(source Identifier, code string, func NewNumericReply(source Identifier, code int,
format string, args ...interface{}) *NumericReply { format string, args ...interface{}) *NumericReply {
return &NumericReply{BasicReply{source, code, fmt.Sprintf(format, args...)}} return &NumericReply{BaseReply{source, fmt.Sprintf(format, args...)}, code}
} }
func (reply NumericReply) Format(client *Client) string { func (reply *NumericReply) Format(client *Client) string {
return fmt.Sprintf(":%s %s %s %s\r\n", reply.source.Id(), reply.code, client.Nick(), return fmt.Sprintf(":%s %03d %s %s", reply.Source().Id(), reply.code,
reply.message) client.Nick(), reply.message)
}
func (reply *NumericReply) String() string {
return fmt.Sprintf("Reply(source=%s, code=%d, message=%s)",
reply.source, reply.code, reply.message)
} }
// messaging replies // messaging replies
func RplPrivMsg(source Identifier, target Identifier, message string) Reply { func RplPrivMsg(source Identifier, target Identifier, message string) Reply {
return NewBasicReply(source, RPL_PRIVMSG, "%s :%s", target.Nick(), message) return NewStringReply(source, RPL_PRIVMSG, "%s :%s", target.Nick(), message)
} }
func RplNick(client *Client, newNick string) Reply { func RplNick(client *Client, newNick string) Reply {
return NewBasicReply(client, RPL_NICK, newNick) return NewStringReply(client, RPL_NICK, newNick)
} }
func RplPrivMsgChannel(channel *Channel, source Identifier, message string) Reply { func RplPrivMsgChannel(channel *Channel, source Identifier, message string) Reply {
return NewBasicReply(source, RPL_PRIVMSG, "%s :%s", channel.name, message) return NewStringReply(source, RPL_PRIVMSG, "%s :%s", channel.name, message)
} }
func RplJoin(channel *Channel, user *User) Reply { func RplJoin(channel *Channel, user *User) Reply {
return NewBasicReply(user, RPL_JOIN, channel.name) return NewStringReply(user, RPL_JOIN, channel.name)
} }
func RplPart(channel *Channel, user *User, message string) Reply { func RplPart(channel *Channel, user *User, message string) Reply {
return NewBasicReply(user, RPL_PART, "%s :%s", channel.name, message) return NewStringReply(user, RPL_PART, "%s :%s", channel.name, message)
} }
func RplPong(server *Server) Reply { func RplPong(server *Server) Reply {
return NewBasicReply(server, RPL_PONG, server.Id()) return NewStringReply(server, RPL_PONG, server.Id())
} }
func RplQuit(client *Client, message string) Reply { func RplQuit(client *Client, message string) Reply {
return NewBasicReply(client, RPL_QUIT, ":%", message) return NewStringReply(client, RPL_QUIT, ":%s", message)
} }
func RplInviteMsg(channel *Channel, inviter *Client) Reply { func RplInviteMsg(channel *Channel, inviter *Client) Reply {
return NewBasicReply(inviter, RPL_INVITE, channel.name) return NewStringReply(inviter, RPL_INVITE, channel.name)
} }
// numeric replies // numeric replies

View File

@ -99,7 +99,7 @@ func (s Server) InterestedUsers(fromUser *User) UserSet {
// server functionality // server functionality
func (s *Server) tryRegister(c *Client) { func (s *Server) tryRegister(c *Client) {
if !c.registered && c.HasNick() && c.HasUser() && (s.password == nil || c.serverPass) { if !c.registered && c.HasNick() && c.HasUsername() && (s.password == nil || c.serverPass) {
c.registered = true c.registered = true
replies := []Reply{RplWelcome(s, c), RplYourHost(s, c), RplCreated(s), RplMyInfo(s)} replies := []Reply{RplWelcome(s, c), RplYourHost(s, c), RplCreated(s), RplMyInfo(s)}
for _, reply := range replies { for _, reply := range replies {
@ -112,15 +112,15 @@ func (s Server) Id() string {
return s.name return s.name
} }
func (s Server) String() string { func (s *Server) String() string {
return s.Id() return s.Id()
} }
func (s Server) PublicId() string { func (s *Server) PublicId() string {
return s.Id() return s.Id()
} }
func (s Server) Nick() string { func (s *Server) Nick() string {
return s.name return s.name
} }
@ -132,7 +132,7 @@ func (s *Server) DeleteChannel(channel *Channel) {
// commands // commands
// //
func (m UnknownCommand) HandleServer(s *Server) { func (m *UnknownCommand) HandleServer(s *Server) {
m.Client().Replies() <- ErrUnknownCommand(s, m.command) m.Client().Replies() <- ErrUnknownCommand(s, m.command)
} }

View File

@ -50,19 +50,19 @@ func receiveCommands(service Service, commands <-chan ServiceCommand) {
} }
} }
func (service BaseService) Id() string { func (service *BaseService) Id() string {
return fmt.Sprintf("%s!%s@%s", service.name, service.name, service.server.name) return fmt.Sprintf("%s!%s@%s", service.name, service.name, service.server.name)
} }
func (service BaseService) String() string { func (service *BaseService) String() string {
return service.Id() return service.Id()
} }
func (service BaseService) PublicId() string { func (service *BaseService) PublicId() string {
return service.Id() return service.Id()
} }
func (service BaseService) Nick() string { func (service *BaseService) Nick() string {
return service.name return service.name
} }
@ -70,10 +70,14 @@ func (service *BaseService) Reply(client *Client, message string) {
client.Replies() <- RplPrivMsg(service, client, message) client.Replies() <- RplPrivMsg(service, client, message)
} }
func (service BaseService) Commands() chan<- ServiceCommand { func (service *BaseService) Commands() chan<- ServiceCommand {
return service.commands return service.commands
} }
//
// commands
//
func (m *PrivMsgCommand) HandleService(service Service) { func (m *PrivMsgCommand) HandleService(service Service) {
service.HandlePrivMsg(m) service.HandlePrivMsg(m)
} }

View File

@ -6,6 +6,10 @@ import (
"log" "log"
) )
const (
DEBUG_USER = true
)
type UserCommand interface { type UserCommand interface {
Command Command
HandleUser(*User) HandleUser(*User)
@ -44,6 +48,7 @@ func NewUser(nick string, password string, server *Server) *User {
user.SetPassword(password) user.SetPassword(password)
go user.receiveCommands(commands) go user.receiveCommands(commands)
go user.receiveReplies(replies) go user.receiveReplies(replies)
server.users[nick] = user
return user return user
} }
@ -57,7 +62,9 @@ func (user *User) SetPassword(password string) {
func (user *User) receiveCommands(commands <-chan UserCommand) { func (user *User) receiveCommands(commands <-chan UserCommand) {
for command := range commands { for command := range commands {
log.Printf("%s %T %+v", user.Id(), command, command) if DEBUG_USER {
log.Printf("%s ← %s %s", user, command.Client(), command)
}
command.HandleUser(user) command.HandleUser(user)
} }
} }
@ -65,7 +72,7 @@ func (user *User) receiveCommands(commands <-chan UserCommand) {
// Distribute replies to clients. // Distribute replies to clients.
func (user *User) receiveReplies(replies <-chan Reply) { func (user *User) receiveReplies(replies <-chan Reply) {
for reply := range replies { for reply := range replies {
log.Printf("%s %T %+v", user.Id(), reply, reply) log.Printf("%s ← %s", user, reply)
for client := range user.clients { for client := range user.clients {
client.Replies() <- reply client.Replies() <- reply
} }
@ -74,19 +81,23 @@ func (user *User) receiveReplies(replies <-chan Reply) {
// Identifier // Identifier
func (user User) Id() string { func (user *User) Id() string {
return fmt.Sprintf("%s!%s@%s", user.nick, user.nick, user.server.Id()) return fmt.Sprintf("%s!%s@%s", user.nick, user.nick, user.server.Id())
} }
func (user User) PublicId() string { func (user *User) PublicId() string {
return user.Id() return user.Id()
} }
func (user User) Nick() string { func (user *User) Nick() string {
return user.nick return user.nick
} }
func (user User) Commands() chan<- UserCommand { func (user *User) String() string {
return user.Id()
}
func (user *User) Commands() chan<- UserCommand {
return user.commands return user.commands
} }
@ -123,11 +134,11 @@ func (user *User) LogoutClient(c *Client) bool {
return false return false
} }
func (user User) HasClients() bool { func (user *User) HasClients() bool {
return len(user.clients) > 0 return len(user.clients) > 0
} }
func (user User) Replies() chan<- Reply { func (user *User) Replies() chan<- Reply {
return user.replies return user.replies
} }