Per-user connections

This commit is contained in:
Simon Ser 2020-02-07 11:36:42 +01:00
parent 7abf426447
commit 3b2bb58c60
No known key found for this signature in database
GPG Key ID: 0FDE7BE0E88F5E48
4 changed files with 66 additions and 32 deletions

View File

@ -15,20 +15,18 @@ func main() {
log.Fatalf("failed to start listener: %v", err) log.Fatalf("failed to start listener: %v", err)
} }
srv := jounce.NewServer()
// TODO: load from config/DB // TODO: load from config/DB
s := jounce.Server{ srv.Hostname = "localhost"
Hostname: "localhost", srv.Upstreams = []jounce.Upstream{{
Logger: log.New(log.Writer(), "", log.LstdFlags),
Upstreams: []jounce.Upstream{{
Addr: "chat.freenode.net:6697", Addr: "chat.freenode.net:6697",
Nick: "jounce", Nick: "jounce",
Username: "jounce", Username: "jounce",
Realname: "jounce", Realname: "jounce",
Channels: []string{"#jounce"}, Channels: []string{"#jounce"},
}}, }}
}
log.Printf("Server listening on %v", addr) log.Printf("Server listening on %v", addr)
go s.Run() go srv.Run()
log.Fatal(s.Serve(ln)) log.Fatal(srv.Serve(ln))
} }

View File

@ -46,6 +46,7 @@ type downstreamConn struct {
messages chan<- *irc.Message messages chan<- *irc.Message
registered bool registered bool
user *user
closed bool closed bool
nick string nick string
username string username string
@ -166,40 +167,50 @@ func (c *downstreamConn) handleMessageUnregistered(msg *irc.Message) error {
} }
func (c *downstreamConn) register() error { func (c *downstreamConn) register() error {
c.srv.lock.Lock()
u, ok := c.srv.users[c.username]
c.srv.lock.Unlock()
if !ok {
c.messages <- &irc.Message{
Prefix: c.srv.prefix(),
Command: irc.ERR_PASSWDMISMATCH,
Params: []string{"*", "Invalid username or password"},
}
return nil
}
c.registered = true c.registered = true
c.user = u
c.messages <- &irc.Message{ c.messages <- &irc.Message{
Prefix: c.srv.prefix(), Prefix: c.srv.prefix(),
Command: irc.RPL_WELCOME, Command: irc.RPL_WELCOME,
Params: []string{c.nick, "Welcome to jounce, " + c.nick}, Params: []string{c.nick, "Welcome to jounce, " + c.nick},
} }
c.messages <- &irc.Message{ c.messages <- &irc.Message{
Prefix: c.srv.prefix(), Prefix: c.srv.prefix(),
Command: irc.RPL_YOURHOST, Command: irc.RPL_YOURHOST,
Params: []string{c.nick, "Your host is " + c.srv.Hostname}, Params: []string{c.nick, "Your host is " + c.srv.Hostname},
} }
c.messages <- &irc.Message{ c.messages <- &irc.Message{
Prefix: c.srv.prefix(), Prefix: c.srv.prefix(),
Command: irc.RPL_CREATED, Command: irc.RPL_CREATED,
Params: []string{c.nick, "This server was created <datetime>"}, // TODO Params: []string{c.nick, "This server was created <datetime>"}, // TODO
} }
c.messages <- &irc.Message{ c.messages <- &irc.Message{
Prefix: c.srv.prefix(), Prefix: c.srv.prefix(),
Command: irc.RPL_MYINFO, Command: irc.RPL_MYINFO,
Params: []string{c.nick, c.srv.Hostname, "jounce", "aiwroO", "OovaimnqpsrtklbeI"}, Params: []string{c.nick, c.srv.Hostname, "jounce", "aiwroO", "OovaimnqpsrtklbeI"},
} }
c.messages <- &irc.Message{ c.messages <- &irc.Message{
Prefix: c.srv.prefix(), Prefix: c.srv.prefix(),
Command: irc.ERR_NOMOTD, Command: irc.ERR_NOMOTD,
Params: []string{c.nick, "No MOTD"}, Params: []string{c.nick, "No MOTD"},
} }
c.srv.lock.Lock() u.lock.Lock()
for _, uc := range c.srv.upstreamConns { for _, uc := range u.upstreamConns {
// TODO: fix races accessing upstream connection data // TODO: fix races accessing upstream connection data
if !uc.registered { if !uc.registered {
continue continue
@ -210,7 +221,7 @@ func (c *downstreamConn) register() error {
} }
} }
} }
c.srv.lock.Unlock() u.lock.Unlock()
return nil return nil
} }

View File

@ -2,6 +2,7 @@ package jounce
import ( import (
"fmt" "fmt"
"log"
"net" "net"
"sync" "sync"
@ -30,6 +31,14 @@ func (l *prefixLogger) Printf(format string, v ...interface{}) {
l.logger.Printf("%v"+format, v...) l.logger.Printf("%v"+format, v...)
} }
type user struct {
username string
srv *Server
lock sync.Mutex
upstreamConns []*upstreamConn
}
type Upstream struct { type Upstream struct {
Addr string Addr string
Nick string Nick string
@ -44,8 +53,15 @@ type Server struct {
Upstreams []Upstream // TODO: per-user Upstreams []Upstream // TODO: per-user
lock sync.Mutex lock sync.Mutex
users map[string]*user
downstreamConns []*downstreamConn downstreamConns []*downstreamConn
upstreamConns []*upstreamConn }
func NewServer() *Server {
return &Server{
Logger: log.New(log.Writer(), "", log.LstdFlags),
users: make(map[string]*user),
}
} }
func (s *Server) prefix() *irc.Prefix { func (s *Server) prefix() *irc.Prefix {
@ -53,32 +69,39 @@ func (s *Server) prefix() *irc.Prefix {
} }
func (s *Server) Run() { func (s *Server) Run() {
// TODO: multi-user
u := &user{username: "jounce", srv: s}
s.lock.Lock()
s.users[u.username] = u
s.lock.Unlock()
for i := range s.Upstreams { for i := range s.Upstreams {
upstream := &s.Upstreams[i] upstream := &s.Upstreams[i]
// TODO: retry connecting // TODO: retry connecting
go func() { go func() {
conn, err := connectToUpstream(s, upstream) conn, err := connectToUpstream(u, upstream)
if err != nil { if err != nil {
s.Logger.Printf("failed to connect to upstream server %q: %v", upstream.Addr, err) s.Logger.Printf("failed to connect to upstream server %q: %v", upstream.Addr, err)
return return
} }
s.lock.Lock() u.lock.Lock()
s.upstreamConns = append(s.upstreamConns, conn) u.upstreamConns = append(u.upstreamConns, conn)
s.lock.Unlock() u.lock.Unlock()
if err := conn.readMessages(); err != nil { if err := conn.readMessages(); err != nil {
conn.logger.Printf("failed to handle messages: %v", err) conn.logger.Printf("failed to handle messages: %v", err)
} }
s.lock.Lock() u.lock.Lock()
for i, c := range s.upstreamConns { for i, c := range u.upstreamConns {
if c == conn { if c == conn {
s.upstreamConns = append(s.upstreamConns[:i], s.upstreamConns[i+1:]...) u.upstreamConns = append(u.upstreamConns[:i], u.upstreamConns[i+1:]...)
break break
} }
} }
s.lock.Unlock() u.lock.Unlock()
}() }()
} }
} }

View File

@ -29,6 +29,7 @@ type upstreamConn struct {
net net.Conn net net.Conn
irc *irc.Conn irc *irc.Conn
srv *Server srv *Server
user *user
messages chan<- *irc.Message messages chan<- *irc.Message
serverName string serverName string
@ -42,8 +43,8 @@ type upstreamConn struct {
channels map[string]*upstreamChannel channels map[string]*upstreamChannel
} }
func connectToUpstream(s *Server, upstream *Upstream) (*upstreamConn, error) { func connectToUpstream(u *user, upstream *Upstream) (*upstreamConn, error) {
logger := &prefixLogger{s.Logger, fmt.Sprintf("upstream %q: ", upstream.Addr)} logger := &prefixLogger{u.srv.Logger, fmt.Sprintf("upstream %q: ", upstream.Addr)}
logger.Printf("connecting to server") logger.Printf("connecting to server")
netConn, err := tls.Dial("tcp", upstream.Addr, nil) netConn, err := tls.Dial("tcp", upstream.Addr, nil)
@ -57,7 +58,8 @@ func connectToUpstream(s *Server, upstream *Upstream) (*upstreamConn, error) {
logger: logger, logger: logger,
net: netConn, net: netConn,
irc: irc.NewConn(netConn), irc: irc.NewConn(netConn),
srv: s, srv: u.srv,
user: u,
messages: msgs, messages: msgs,
channels: make(map[string]*upstreamChannel), channels: make(map[string]*upstreamChannel),
} }