hid: use time.Time and time.Duration

It improves the code significantly over explicit int64 conversions.

Despite carrying unnecessary timezone information, time.Time also
carries a monotonic reading of time, which allows for more precise
measurement of time differences.
This commit is contained in:
Přemysl Eric Janouch 2018-07-30 10:04:05 +02:00
parent 40370702d4
commit 24f1c4413a
Signed by: p
GPG Key ID: A0420B94F92B9493
1 changed files with 42 additions and 45 deletions

View File

@ -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)