wip
--HG-- branch : nmdc-ircfrontend
This commit is contained in:
parent
a9f1283dd6
commit
be5715a562
53
client.go
53
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()
|
||||
}()
|
||||
|
||||
|
17
main.go
17
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)
|
||||
}
|
||||
}
|
||||
|
83
server.go
83
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 {
|
||||
|
32
typedefs.go
32
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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user