summaryrefslogtreecommitdiff
path: root/xS/main.go
diff options
context:
space:
mode:
Diffstat (limited to 'xS/main.go')
-rw-r--r--xS/main.go87
1 files changed, 42 insertions, 45 deletions
diff --git a/xS/main.go b/xS/main.go
index ff6a84a..1c72fca 100644
--- a/xS/main.go
+++ b/xS/main.go
@@ -46,11 +46,6 @@ const (
projectVersion = "0"
)
-// TODO: Consider using time.Time directly instead of storing Unix epoch
-// timestamps with nanosecond precision. Despite carrying unnecessary timezone
-// information, it also carries a monotonic reading of the time, which allows
-// for more precise measurement of time differences.
-
// --- Utilities ---------------------------------------------------------------
// Split a string by a set of UTF-8 delimiters, optionally ignoring empty items.
@@ -207,23 +202,23 @@ func readConfigFile(name string, output interface{}) error {
// --- Rate limiter ------------------------------------------------------------
type floodDetector struct {
- interval uint // interval for the limit in seconds
- limit uint // maximum number of events allowed
- timestamps []int64 // timestamps of last events
- pos uint // index of the oldest event
+ interval time.Duration // interval for the limit in seconds
+ limit uint // maximum number of events allowed
+ timestamps []time.Time // timestamps of last events
+ pos uint // index of the oldest event
}
-func newFloodDetector(interval, limit uint) *floodDetector {
+func newFloodDetector(interval time.Duration, limit uint) *floodDetector {
return &floodDetector{
interval: interval,
limit: limit,
- timestamps: make([]int64, limit+1),
+ timestamps: make([]time.Time, limit+1),
pos: 0,
}
}
func (fd *floodDetector) check() bool {
- now := time.Now().UnixNano()
+ now := time.Now()
fd.timestamps[fd.pos] = now
fd.pos++
@@ -232,9 +227,9 @@ func (fd *floodDetector) check() bool {
}
var count uint
- begin := now - int64(time.Second)*int64(fd.interval)
+ begin := now.Add(-fd.interval)
for _, ts := range fd.timestamps {
- if ts >= begin {
+ if ts.After(begin) {
count++
}
}
@@ -402,11 +397,11 @@ type client struct {
closing bool // whether we're closing the connection
killTimer *time.Timer // hard kill timeout
- opened int64 // when the connection was opened
- nSentMessages uint // number of sent messages total
- sentBytes int // number of sent bytes total
- nReceivedMessages uint // number of received messages total
- receivedBytes int // number of received bytes total
+ opened time.Time // when the connection was opened
+ nSentMessages uint // number of sent messages total
+ sentBytes int // number of sent bytes total
+ nReceivedMessages uint // number of received messages total
+ receivedBytes int // number of received bytes total
hostname string // hostname or IP shown to the network
port string // port of the peer as a string
@@ -427,9 +422,9 @@ type client struct {
mode uint // user's mode
awayMessage string // away message
- lastActive int64 // last PRIVMSG, to get idle time
+ lastActive time.Time // last PRIVMSG, to get idle time
invites map[string]bool // channel invitations by operators
- antiflood floodDetector // flood detector
+ antiflood *floodDetector // flood detector
}
// --- Channels ----------------------------------------------------------------
@@ -450,15 +445,15 @@ const (
)
type channel struct {
- name string // channel name
- modes uint // channel modes
- key string // channel key
- userLimit int // user limit or -1
- created int64 // creation time
+ name string // channel name
+ modes uint // channel modes
+ key string // channel key
+ userLimit int // user limit or -1
+ created time.Time // creation time
- topic string // channel topic
- topicWho string // who set the topic
- topicTime int64 // when the topic was set
+ topic string // channel topic
+ topicWho string // who set the topic
+ topicTime time.Time // when the topic was set
userModes map[*client]uint // modes for all channel users
@@ -557,7 +552,7 @@ type writeEvent struct {
// XXX: Beware that maps with identifier keys need to be indexed correctly.
// We might want to enforce accessor functions for users and channels.
var (
- started int64 // when has the server been started
+ started time.Time // when has the server been started
users map[string]*client // maps nicknames to clients
channels map[string]*channel // maps channel names to data
@@ -616,7 +611,7 @@ func initiateQuit() {
func ircChannelCreate(name string) *channel {
ch := &channel{
name: name,
- created: time.Now().UnixNano(),
+ created: time.Now(),
userLimit: -1,
}
channels[ircToCanon(name)] = ch
@@ -941,7 +936,7 @@ func (c *client) tryFinishRegistration() {
c.sendReply(RPL_YOURHOST, serverName, projectVersion)
// The purpose of this message eludes me.
- c.sendReply(RPL_CREATED, time.Unix(started, 0).Format("Mon, 02 Jan 2006"))
+ c.sendReply(RPL_CREATED, started.Format("Mon, 02 Jan 2006"))
c.sendReply(RPL_MYINFO, serverName, projectVersion,
ircSupportedUserModes, ircSupportedChanModes)
@@ -1691,8 +1686,7 @@ func ircHandleMODE(msg *message, c *client) {
if len(msg.params) < 2 {
_, present := ch.userModes[c]
c.sendReply(RPL_CHANNELMODEIS, target, ch.getMode(present))
- c.sendReply(RPL_CREATIONTIME,
- target, ch.created/int64(time.Second))
+ c.sendReply(RPL_CREATIONTIME, target, ch.created.Unix())
} else {
ircHandleChanModeChange(c, ch, msg.params[1:])
}
@@ -1752,8 +1746,7 @@ func ircHandleUserMessage(msg *message, c *client,
func ircHandlePRIVMSG(msg *message, c *client) {
ircHandleUserMessage(msg, c, "PRIVMSG", true /* allowAwayReply */)
- // Let's not care too much about success or failure.
- c.lastActive = time.Now().UnixNano()
+ c.lastActive = time.Now()
}
func ircHandleNOTICE(msg *message, c *client) {
@@ -1980,7 +1973,7 @@ func ircSendWHOISReply(c, target *client) {
c.sendReply(RPL_WHOISOPERATOR, nick)
}
c.sendReply(RPL_WHOISIDLE, nick,
- (time.Now().UnixNano()-target.lastActive)/int64(time.Second))
+ time.Now().Sub(target.lastActive)/time.Second)
if target.awayMessage != "" {
c.sendReply(RPL_AWAY, nick, target.awayMessage)
}
@@ -2073,7 +2066,7 @@ func ircSendRPLTOPIC(c *client, ch *channel) {
} else {
c.sendReply(RPL_TOPIC, ch.name, ch.topic)
c.sendReply(RPL_TOPICWHOTIME,
- ch.name, ch.topicWho, ch.topicTime/int64(time.Second))
+ ch.name, ch.topicWho, ch.topicTime.Unix())
}
}
@@ -2109,7 +2102,7 @@ func ircHandleTOPIC(msg *message, c *client) {
ch.topic = msg.params[1]
ch.topicWho = fmt.Sprintf("%s@%s@%s", c.nickname, c.username, c.hostname)
- ch.topicTime = time.Now().UnixNano()
+ ch.topicTime = time.Now()
message := fmt.Sprintf(":%s!%s@%s TOPIC %s :%s",
c.nickname, c.username, c.hostname, target, ch.topic)
@@ -2418,7 +2411,7 @@ func ircHandleStatsLinks(c *client, msg *message) {
len(client.sendQ), // sendq
client.nSentMessages, client.sentBytes/1024,
client.nReceivedMessages, client.receivedBytes/1024,
- (time.Now().UnixNano()-client.opened)/int64(time.Second))
+ time.Now().Sub(client.opened)/time.Second)
}
}
@@ -2440,7 +2433,7 @@ func init() {
}
func ircHandleStatsUptime(c *client) {
- uptime := (time.Now().UnixNano() - started) / int64(time.Second)
+ uptime := time.Now().Sub(started) / time.Second
days := uptime / 60 / 60 / 24
hours := (uptime % (60 * 60 * 24)) / 60 / 60
@@ -2811,10 +2804,13 @@ func processOneEvent() {
}
c := &client{
- transport: conn,
- address: address,
- hostname: host,
- port: port,
+ transport: conn,
+ address: address,
+ hostname: host,
+ port: port,
+ capVersion: 301,
+ // TODO: Make this configurable and more fine-grained.
+ antiflood: newFloodDetector(10*time.Second, 20),
}
clients[c] = true
go prepare(c)
@@ -2875,6 +2871,7 @@ func main() {
log.Fatalln(err)
}
+ started = time.Now()
go accept(listener)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)