Per-user connections
This commit is contained in:
parent
7abf426447
commit
3b2bb58c60
@ -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))
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
41
server.go
41
server.go
@ -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()
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user