Remove signal processor for password reloading and use pointers to strings
Simplify code and server maintaining by removing password file caching and refreshing it with HUP signal. Also use pointers to strings, already presented after flag-module work.
This commit is contained in:
parent
85e6538f2f
commit
990937d451
@ -31,7 +31,7 @@ const (
|
||||
)
|
||||
|
||||
type Client struct {
|
||||
hostname string
|
||||
hostname *string
|
||||
conn net.Conn
|
||||
registered bool
|
||||
nickname string
|
||||
@ -49,7 +49,7 @@ func (client Client) String() string {
|
||||
return client.nickname + "!" + client.username + "@" + client.conn.RemoteAddr().String()
|
||||
}
|
||||
|
||||
func NewClient(hostname string, conn net.Conn) *Client {
|
||||
func NewClient(hostname *string, conn net.Conn) *Client {
|
||||
return &Client{hostname: hostname, conn: conn, nickname: "*", password: ""}
|
||||
}
|
||||
|
||||
@ -89,7 +89,7 @@ func (client *Client) Msg(text string) {
|
||||
|
||||
// Send message from server. It has ": servername" prefix.
|
||||
func (client *Client) Reply(text string) {
|
||||
client.Msg(":" + client.hostname + " " + text)
|
||||
client.Msg(":" + *client.hostname + " " + text)
|
||||
}
|
||||
|
||||
// Send server message, concatenating all provided text parts and
|
||||
|
@ -96,7 +96,8 @@ func (conn TestingConn) SetWriteDeadline(t time.Time) error {
|
||||
func TestNewClient(t *testing.T) {
|
||||
conn := NewTestingConn()
|
||||
sink := make(chan ClientEvent)
|
||||
client := NewClient("foohost", conn)
|
||||
host := "foohost"
|
||||
client := NewClient(&host, conn)
|
||||
go client.Processor(sink)
|
||||
|
||||
event := <-sink
|
||||
@ -123,7 +124,8 @@ func TestNewClient(t *testing.T) {
|
||||
// Test replies formatting
|
||||
func TestClientReplies(t *testing.T) {
|
||||
conn := NewTestingConn()
|
||||
client := NewClient("foohost", conn)
|
||||
host := "foohost"
|
||||
client := NewClient(&host, conn)
|
||||
client.nickname = "мойник"
|
||||
|
||||
client.Reply("hello")
|
||||
|
81
daemon.go
81
daemon.go
@ -25,7 +25,6 @@ import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -39,13 +38,12 @@ var (
|
||||
RENickname = regexp.MustCompile("^[a-zA-Z0-9-]{1,9}$")
|
||||
)
|
||||
|
||||
var passwordsRefreshLock sync.Mutex
|
||||
|
||||
type Daemon struct {
|
||||
Verbose bool
|
||||
version string
|
||||
hostname string
|
||||
motd string
|
||||
hostname *string
|
||||
motd *string
|
||||
passwords *string
|
||||
clients map[*Client]bool
|
||||
clientAliveness map[*Client]*ClientAlivenessState
|
||||
rooms map[string]*Room
|
||||
@ -53,11 +51,10 @@ type Daemon struct {
|
||||
lastAlivenessCheck time.Time
|
||||
logSink chan<- LogEvent
|
||||
stateSink chan<- StateEvent
|
||||
passwords map[string]string
|
||||
}
|
||||
|
||||
func NewDaemon(version, hostname, motd string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Daemon {
|
||||
daemon := Daemon{version: version, hostname: hostname, motd: motd}
|
||||
func NewDaemon(version string, hostname, motd, passwords *string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Daemon {
|
||||
daemon := Daemon{version: version, hostname: hostname, motd: motd, passwords: passwords}
|
||||
daemon.clients = make(map[*Client]bool)
|
||||
daemon.clientAliveness = make(map[*Client]*ClientAlivenessState)
|
||||
daemon.rooms = make(map[string]*Room)
|
||||
@ -78,19 +75,19 @@ func (daemon *Daemon) SendLusers(client *Client) {
|
||||
}
|
||||
|
||||
func (daemon *Daemon) SendMotd(client *Client) {
|
||||
if len(daemon.motd) == 0 {
|
||||
if daemon.motd == nil || *daemon.motd == "" {
|
||||
client.ReplyNicknamed("422", "MOTD File is missing")
|
||||
return
|
||||
}
|
||||
|
||||
motd, err := ioutil.ReadFile(daemon.motd)
|
||||
motd, err := ioutil.ReadFile(*daemon.motd)
|
||||
if err != nil {
|
||||
log.Printf("Can not read motd file %s: %v", daemon.motd, err)
|
||||
log.Printf("Can not read motd file %s: %v", *daemon.motd, err)
|
||||
client.ReplyNicknamed("422", "Error reading MOTD File")
|
||||
return
|
||||
}
|
||||
|
||||
client.ReplyNicknamed("375", "- "+daemon.hostname+" Message of the day -")
|
||||
client.ReplyNicknamed("375", "- "+*daemon.hostname+" Message of the day -")
|
||||
for _, s := range strings.Split(strings.Trim(string(motd), "\n"), "\n") {
|
||||
client.ReplyNicknamed("372", "- "+string(s))
|
||||
}
|
||||
@ -113,7 +110,7 @@ func (daemon *Daemon) SendWhois(client *Client, nicknames []string) {
|
||||
h = "Unknown"
|
||||
}
|
||||
client.ReplyNicknamed("311", c.nickname, c.username, h, "*", c.realname)
|
||||
client.ReplyNicknamed("312", c.nickname, daemon.hostname, daemon.hostname)
|
||||
client.ReplyNicknamed("312", c.nickname, *daemon.hostname, *daemon.hostname)
|
||||
subscriptions := []string{}
|
||||
for _, room := range daemon.rooms {
|
||||
for subscriber := range room.members {
|
||||
@ -196,19 +193,34 @@ func (daemon *Daemon) ClientRegister(client *Client, command string, cols []stri
|
||||
client.realname = strings.TrimLeft(args[3], ":")
|
||||
}
|
||||
if client.nickname != "*" && client.username != "" {
|
||||
passwordsRefreshLock.Lock()
|
||||
if daemon.passwords != nil && (client.password == "" || daemon.passwords[client.nickname] != client.password) {
|
||||
passwordsRefreshLock.Unlock()
|
||||
client.ReplyParts("462", "You may not register")
|
||||
client.conn.Close()
|
||||
return
|
||||
if daemon.passwords != nil && *daemon.passwords != "" {
|
||||
if client.password == "" {
|
||||
client.ReplyParts("462", "You may not register")
|
||||
client.conn.Close()
|
||||
return
|
||||
}
|
||||
contents, err := ioutil.ReadFile(*daemon.passwords)
|
||||
if err != nil {
|
||||
log.Fatalf("Can no read passwords file %s: %s", *daemon.passwords, err)
|
||||
return
|
||||
}
|
||||
for _, entry := range strings.Split(string(contents), "\n") {
|
||||
if entry == "" {
|
||||
continue
|
||||
}
|
||||
if lp := strings.Split(entry, ":"); lp[0] == client.nickname && lp[1] != client.password {
|
||||
client.ReplyParts("462", "You may not register")
|
||||
client.conn.Close()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
passwordsRefreshLock.Unlock()
|
||||
|
||||
client.registered = true
|
||||
client.ReplyNicknamed("001", "Hi, welcome to IRC")
|
||||
client.ReplyNicknamed("002", "Your host is "+daemon.hostname+", running goircd "+daemon.version)
|
||||
client.ReplyNicknamed("002", "Your host is "+*daemon.hostname+", running goircd "+daemon.version)
|
||||
client.ReplyNicknamed("003", "This server was created sometime")
|
||||
client.ReplyNicknamed("004", daemon.hostname+" goircd o o")
|
||||
client.ReplyNicknamed("004", *daemon.hostname+" goircd o o")
|
||||
daemon.SendLusers(client)
|
||||
daemon.SendMotd(client)
|
||||
log.Println(client, "logged in")
|
||||
@ -295,7 +307,7 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) {
|
||||
}
|
||||
if !aliveness.pingSent && aliveness.timestamp.Add(PingThreshold).Before(now) {
|
||||
if c.registered {
|
||||
c.Msg("PING :" + daemon.hostname)
|
||||
c.Msg("PING :" + *daemon.hostname)
|
||||
aliveness.pingSent = true
|
||||
} else {
|
||||
log.Println(c, "ping timeout")
|
||||
@ -391,7 +403,7 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) {
|
||||
client.ReplyNicknamed("409", "No origin specified")
|
||||
continue
|
||||
}
|
||||
client.Reply(fmt.Sprintf("PONG %s :%s", daemon.hostname, cols[1]))
|
||||
client.Reply(fmt.Sprintf("PONG %s :%s", *daemon.hostname, cols[1]))
|
||||
case "PONG":
|
||||
continue
|
||||
case "NOTICE", "PRIVMSG":
|
||||
@ -466,7 +478,7 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) {
|
||||
} else {
|
||||
debug = ""
|
||||
}
|
||||
client.ReplyNicknamed("351", fmt.Sprintf("%s.%s %s :", daemon.version, debug, daemon.hostname))
|
||||
client.ReplyNicknamed("351", fmt.Sprintf("%s.%s %s :", daemon.version, debug, *daemon.hostname))
|
||||
default:
|
||||
client.ReplyNicknamed("421", command, "Unknown command")
|
||||
}
|
||||
@ -477,22 +489,3 @@ func (daemon *Daemon) Processor(events <-chan ClientEvent) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (daemon *Daemon) PasswordsRefresh() {
|
||||
contents, err := ioutil.ReadFile(*passwords)
|
||||
if err != nil {
|
||||
log.Fatalf("Can no read passwords file %s: %s", *passwords, err)
|
||||
return
|
||||
}
|
||||
processed := make(map[string]string)
|
||||
for _, entry := range strings.Split(string(contents), "\n") {
|
||||
loginAndPassword := strings.Split(entry, ":")
|
||||
if len(loginAndPassword) == 2 {
|
||||
processed[loginAndPassword[0]] = loginAndPassword[1]
|
||||
}
|
||||
}
|
||||
log.Printf("Read %d passwords", len(processed))
|
||||
passwordsRefreshLock.Lock()
|
||||
daemon.passwords = processed
|
||||
passwordsRefreshLock.Unlock()
|
||||
}
|
||||
|
@ -25,11 +25,12 @@ import (
|
||||
)
|
||||
|
||||
func TestRegistrationWorkflow(t *testing.T) {
|
||||
daemon := NewDaemon("ver1", "foohost", "", nil, nil)
|
||||
host := "foohost"
|
||||
daemon := NewDaemon("ver1", &host, nil, nil, nil, nil)
|
||||
events := make(chan ClientEvent)
|
||||
go daemon.Processor(events)
|
||||
conn := NewTestingConn()
|
||||
client := NewClient("foohost", conn)
|
||||
client := NewClient(&host, conn)
|
||||
go client.Processor(events)
|
||||
|
||||
conn.inbound <- "UNEXISTENT CMD" // should recieve nothing on this
|
||||
@ -119,8 +120,10 @@ func TestMotd(t *testing.T) {
|
||||
fd.WriteString("catched\n")
|
||||
|
||||
conn := NewTestingConn()
|
||||
client := NewClient("foohost", conn)
|
||||
daemon := NewDaemon("ver1", "foohost", fd.Name(), nil, nil)
|
||||
host := "foohost"
|
||||
client := NewClient(&host, conn)
|
||||
motdName := fd.Name()
|
||||
daemon := NewDaemon("ver1", &host, &motdName, nil, nil, nil)
|
||||
|
||||
daemon.SendMotd(client)
|
||||
if r := <-conn.outbound; !strings.HasPrefix(r, ":foohost 375") {
|
||||
|
22
goircd.go
22
goircd.go
@ -23,12 +23,9 @@ import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -53,7 +50,7 @@ func listenerLoop(sock net.Listener, events chan<- ClientEvent) {
|
||||
log.Println("Error during accepting connection", err)
|
||||
continue
|
||||
}
|
||||
client := NewClient(*hostname, conn)
|
||||
client := NewClient(hostname, conn)
|
||||
go client.Processor(events)
|
||||
}
|
||||
}
|
||||
@ -79,9 +76,9 @@ func Run() {
|
||||
}
|
||||
|
||||
stateSink := make(chan StateEvent)
|
||||
daemon := NewDaemon(version, *hostname, *motd, logSink, stateSink)
|
||||
daemon := NewDaemon(version, hostname, motd, passwords, logSink, stateSink)
|
||||
daemon.Verbose = *verbose
|
||||
log.Println("goircd "+daemon.version+" is starting")
|
||||
log.Println("goircd " + daemon.version + " is starting")
|
||||
if *statedir == "" {
|
||||
// Dummy statekeeper
|
||||
go func() {
|
||||
@ -115,19 +112,6 @@ func Run() {
|
||||
log.Println(*statedir, "statekeeper initialized")
|
||||
}
|
||||
|
||||
if *passwords != "" {
|
||||
daemon.PasswordsRefresh()
|
||||
hups := make(chan os.Signal)
|
||||
signal.Notify(hups, syscall.SIGHUP)
|
||||
go func() {
|
||||
for {
|
||||
<-hups
|
||||
daemon.PasswordsRefresh()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
|
||||
if *bind != "" {
|
||||
listener, err := net.Listen("tcp", *bind)
|
||||
if err != nil {
|
||||
|
10
room.go
10
room.go
@ -41,16 +41,16 @@ type Room struct {
|
||||
topic string
|
||||
key string
|
||||
members map[*Client]bool
|
||||
hostname string
|
||||
hostname *string
|
||||
logSink chan<- LogEvent
|
||||
stateSink chan<- StateEvent
|
||||
}
|
||||
|
||||
func (r Room) String() string {
|
||||
return r.name
|
||||
func (room Room) String() string {
|
||||
return room.name
|
||||
}
|
||||
|
||||
func NewRoom(hostname, name string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Room {
|
||||
func NewRoom(hostname *string, name string, logSink chan<- LogEvent, stateSink chan<- StateEvent) *Room {
|
||||
room := Room{name: name}
|
||||
room.members = make(map[*Client]bool)
|
||||
room.topic = ""
|
||||
@ -128,7 +128,7 @@ func (room *Room) Processor(events <-chan ClientEvent) {
|
||||
room.StateSave()
|
||||
case EventWho:
|
||||
for m := range room.members {
|
||||
client.ReplyNicknamed("352", room.name, m.username, m.conn.RemoteAddr().String(), room.hostname, m.nickname, "H", "0 "+m.realname)
|
||||
client.ReplyNicknamed("352", room.name, m.username, m.conn.RemoteAddr().String(), *room.hostname, m.nickname, "H", "0 "+m.realname)
|
||||
}
|
||||
client.ReplyNicknamed("315", room.name, "End of /WHO list")
|
||||
case EventMode:
|
||||
|
12
room_test.go
12
room_test.go
@ -26,14 +26,15 @@ func notEnoughParams(t *testing.T, c *TestingConn) {
|
||||
func TestTwoUsers(t *testing.T) {
|
||||
logSink := make(chan LogEvent, 8)
|
||||
stateSink := make(chan StateEvent, 8)
|
||||
daemon := NewDaemon("ver1", "foohost", "", logSink, stateSink)
|
||||
host := "foohost"
|
||||
daemon := NewDaemon("ver1", &host, nil, nil, logSink, stateSink)
|
||||
events := make(chan ClientEvent)
|
||||
go daemon.Processor(events)
|
||||
|
||||
conn1 := NewTestingConn()
|
||||
conn2 := NewTestingConn()
|
||||
client1 := NewClient("foohost", conn1)
|
||||
client2 := NewClient("foohost", conn2)
|
||||
client1 := NewClient(&host, conn1)
|
||||
client2 := NewClient(&host, conn2)
|
||||
go client1.Processor(events)
|
||||
go client2.Processor(events)
|
||||
|
||||
@ -100,11 +101,12 @@ func TestTwoUsers(t *testing.T) {
|
||||
func TestJoin(t *testing.T) {
|
||||
logSink := make(chan LogEvent, 8)
|
||||
stateSink := make(chan StateEvent, 8)
|
||||
daemon := NewDaemon("ver1", "foohost", "", logSink, stateSink)
|
||||
host := "foohost"
|
||||
daemon := NewDaemon("ver1", &host, nil, nil, logSink, stateSink)
|
||||
events := make(chan ClientEvent)
|
||||
go daemon.Processor(events)
|
||||
conn := NewTestingConn()
|
||||
client := NewClient("foohost", conn)
|
||||
client := NewClient(&host, conn)
|
||||
go client.Processor(events)
|
||||
|
||||
conn.inbound <- "NICK nick2\r\nUSER foo2 bar2 baz2 :Long name2\r\n"
|
||||
|
Loading…
Reference in New Issue
Block a user