From be5715a562cb58f78c8c92a918f4efe2b35802bf Mon Sep 17 00:00:00 2001 From: "." <.@.> Date: Tue, 3 May 2016 18:25:27 +1200 Subject: [PATCH] wip --HG-- branch : nmdc-ircfrontend --- client.go | 53 ++++++++++++++++------------------ main.go | 17 ++++++----- server.go | 83 ++++++++++++++++++++++++----------------------------- typedefs.go | 32 ++++++--------------- 4 files changed, 78 insertions(+), 107 deletions(-) diff --git a/client.go b/client.go index 99b5740..43d7535 100644 --- a/client.go +++ b/client.go @@ -4,55 +4,51 @@ import ( "bytes" "fmt" "io" + "net" "strings" "time" ) +type Client struct { + server *Server + connection net.Conn + signalChan chan signalCode + outputChan chan string + nick string + key string + registered bool + connected bool + operator bool +} + func (c *Client) joinChannel(channelName string) { newChannel := false channelKey := strings.ToLower(channelName) - channel, exists := c.server.channelMap[channelKey] - if exists == false { - mode := ChannelMode{secret: true, - topicLocked: true, - noExternal: true} - channel = &Channel{name: channelName, - topic: "", - clientMap: make(map[string]*Client), - modeMap: make(map[string]*ClientMode), - mode: mode} - c.server.channelMap[channelKey] = channel - newChannel = true + if channelKey != BLESSED_CHANNEL { + panic("?") } + channel := c.server.channel if _, inChannel := channel.clientMap[c.key]; inChannel { //Client is already in the channel, do nothing return } - mode := new(ClientMode) - if newChannel { - //If they created the channel, make them op - mode.operator = true - } - - channel.clientMap[c.key] = c - channel.modeMap[c.key] = mode - c.channelMap[channelKey] = channel - + // Send notifications to /other/ clients that /we/ joined this room for _, client := range channel.clientMap { - client.reply(rplJoin, c.nick, channel.name) + client.reply(rplJoin, c.nick, BLESSED_CHANNEL) } + // Transmit topic if channel.topic != "" { - c.reply(rplTopic, channel.name, channel.topic) + c.reply(rplTopic, BLESSED_CHANNEL, channel.topic) } else { - c.reply(rplNoTopic, channel.name) + c.reply(rplNoTopic, BLESSED_CHANNEL) } - //The capacity sets the max number of nicks to send per message - nicks := make([]string, 0, 128) + // Transmit the list of joined users to us + nicks := make([]string, 0, NICKS_PER_PROTOMSG) for _, client := range channel.clientMap { prefix := "" @@ -167,8 +163,7 @@ func (c *Client) clientThread() { defer func() { // Implicit part from all channels - - delete(c.server.clientMap, c.key) + // FIXME also drop the upstream connection c.connection.Close() }() diff --git a/main.go b/main.go index ee4c11b..39ef6cd 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "flag" + "libnmdc" "log" "net" ) @@ -15,16 +16,10 @@ var ( func main() { flag.Parse() - - log.Println("Starting server...") - - server := NewServer(*serverName) - - if len(server.name) == 0 { + if len(*serverName) == 0 { log.Println("Please specify the -servername parameter.") return } - server.motd = "Connected to " + *serverName listener, err := net.Listen("tcp", *ircAddress) if err != nil { @@ -32,8 +27,6 @@ func main() { return } - go server.Run() - log.Printf("Listening on %s", *ircAddress) for { @@ -43,6 +36,12 @@ func main() { continue } + // Spin up an IRC server for the new user. + // The upstream connection doesn't get launched until we hear a nick + // from the irc client + + server := NewServer(*serverName, libnmdc.HubAddress(*dcAddress)) + go server.Run() server.HandleConnection(conn) } } diff --git a/server.go b/server.go index d31c73e..412a070 100644 --- a/server.go +++ b/server.go @@ -2,25 +2,29 @@ package main import ( "fmt" - "log" + "libnmdc" "net" - "regexp" "strings" ) -var ( - nickRegexp = regexp.MustCompile(`^[a-zA-Z\[\]_^{|}][a-zA-Z0-9\[\]_^{|}]*$`) - channelRegexp = regexp.MustCompile(`^#[a-zA-Z0-9_\-]+$`) -) +type Server struct { + eventChan chan Event + running bool + name string + client *Client + channel Channel // Single blessed channel + upstreamAddr libnmdc.HubAddress + upstream libnmdc.HubConnection + motd string +} -func NewServer(name string) *Server { +func NewServer(name string, upstream libnmdc.HubAddress) *Server { return &Server{eventChan: make(chan Event), - name: name, - clientMap: make(map[string]*Client), - motd: "", + name: name, + client: nil, + motd: "Connected to " + name, + upstreamAddr: upstream, channel: Channel{ - name: BLESSED_CHANNEL, - topic: name, clientMap: make(map[string]*Client), modeMap: make(map[string]*ClientMode), }, @@ -45,13 +49,6 @@ func (s *Server) HandleConnection(conn net.Conn) { } func (s *Server) handleEvent(e Event) { - defer func(event Event) { - err := recover() - if err != nil { - log.Printf("Recovered from error when handling event: %+v", event) - log.Println(err) - } - }(e) switch e.event { case connected: @@ -104,12 +101,20 @@ func (s *Server) handleCommand(client *Client, command string, args []string) { client.disconnect() case "USER": + if client.registered == true { + client.reply(rplKill, "You're already registered.", "") + client.disconnect() + } + if client.nick == "" { client.reply(rplKill, "Your nickname is already being used", "") client.disconnect() + } else { client.reply(rplWelcome) client.registered = true + + // Spawn } case "JOIN": @@ -155,15 +160,21 @@ func (s *Server) handleCommand(client *Client, command string, args []string) { message := strings.Join(args[1:], " ") - if strings.ToLower(args[0]) == BLESSED_CHANNEL { + // IRC is case-insensitive case-preserving. We can respect that for the + // channel name, but not really for user nicks + recipient := strings.ToLower(args[0]) + + if recipient == BLESSED_CHANNEL { for _, c := range s.channel.clientMap { if c != client { c.reply(rplMsg, client.nick, args[0], message) } } - } else if client2, clientExists := s.clientMap[strings.ToLower(args[0])]; clientExists { - client2.reply(rplMsg, client.nick, client2.nick, message) + } else if nmdcUser, clientExists := s.upstream.Users[args[0]]; clientExists { + + s.upstream.SayPrivate(recipient, message) + // client2.reply(rplMsg, client.nick, client2.nick, message) } else { client.reply(errNoSuchNick, args[0]) @@ -197,7 +208,7 @@ func (s *Server) handleCommand(client *Client, command string, args []string) { // Valid topic get if len(args) == 1 { - client.reply(rplTopic, s.channel.name, s.name) + client.reply(rplTopic, BLESSED_CHANNEL, s.upstream.HubName) return } @@ -211,7 +222,7 @@ func (s *Server) handleCommand(client *Client, command string, args []string) { return } - listItem := fmt.Sprintf("%s %d :%s", s.channel.name, len(s.channel.clientMap), s.channel.topic) + listItem := fmt.Sprintf("%s %d :%s", BLESSED_CHANNEL, len(s.channel.clientMap), s.upstream.HubName) client.reply(rplList, listItem) client.reply(rplListEnd) @@ -244,28 +255,8 @@ func (s *Server) handleCommand(client *Client, command string, args []string) { return } - if client.operator == false { - client.reply(errNoPriv) - return - } - - if len(args) < 1 { - client.reply(errMoreArgs) - return - } - - nick := args[0] - - reason := strings.Join(args[1:], " ") - - client, exists := s.clientMap[strings.ToLower(nick)] - if !exists { - client.reply(errNoSuchNick, nick) - return - } - - client.reply(rplKill, client.nick, reason) - client.disconnect() + client.reply(errNoPriv) + return case "KICK": if client.registered == false { diff --git a/typedefs.go b/typedefs.go index 4ce83c0..28b925d 100644 --- a/typedefs.go +++ b/typedefs.go @@ -1,34 +1,22 @@ package main -import "net" +import ( + "regexp" +) const ( VERSION = "1.0.0" APP_DESCRIPTION = "nmdc-ircfrontend v" + VERSION BLESSED_CHANNEL = "#chat" // must be lowercase BLESSED_CHANNEL_MODE = "n" // means that you have to be in the channel to chat, but that's it + + NICKS_PER_PROTOMSG = 128 //The capacity sets the max number of nicks to send per message ) -type Server struct { - eventChan chan Event - running bool - name string - clientMap map[string]*Client // Map of nicks -> clients - channel Channel // Single blessed channel - motd string -} - -type Client struct { - server *Server - connection net.Conn - signalChan chan signalCode - outputChan chan string - nick string - key string - registered bool - connected bool - operator bool -} +var ( + nickRegexp = regexp.MustCompile(`^[a-zA-Z\[\]_^{|}][a-zA-Z0-9\[\]_^{|}]*$`) + channelRegexp = regexp.MustCompile(`^#[a-zA-Z0-9_\-]+$`) +) type eventType int @@ -45,8 +33,6 @@ type Event struct { } type Channel struct { - name string - topic string clientMap map[string]*Client modeMap map[string]*ClientMode }