diff --git a/chat-plugins/tcgtabletop.js b/chat-plugins/tcgtabletop.js index 860d667fa2..34b71da97a 100644 --- a/chat-plugins/tcgtabletop.js +++ b/chat-plugins/tcgtabletop.js @@ -8,6 +8,8 @@ const http = require('http'); +function noop() {} + function wikiaSearch(subdomain, query, callback) { http.get('http://' + subdomain + '.wikia.com/api/v1/Search/List/?query=' + encodeURIComponent(query) + '&limit=1', res => { let buffer = ''; @@ -28,7 +30,10 @@ function wikiaSearch(subdomain, query, callback) { return callback(null, result.items[0]); }); - }).on('error', callback); + }).once('error', function (err) { + callback(err); + this.on('error', noop); + }); } exports.commands = { @@ -42,7 +47,7 @@ exports.commands = { let subdomain = (cmd === 'yugioh' || cmd === 'ygo') ? 'yugioh' : 'mtg'; let query = target.trim(); - wikiaSearch(subdomain, query, ((err, data) => { + wikiaSearch(subdomain, query, (err, data) => { if (err) { if (err instanceof SyntaxError || err.message === 'Malformed data') { if (!broadcasting) return connection.sendTo(room, "Error: something went wrong in the request: " + err.message); @@ -56,6 +61,6 @@ exports.commands = { let htmlReply = "Best result for " + Tools.escapeHTML(query) + ":
" + Tools.escapeHTML(entryTitle) + ""; if (!broadcasting) return connection.sendTo(room, "|raw|
" + htmlReply + "
"); room.addRaw("
" + htmlReply + "
").update(); - }).once()); + }); }, }; diff --git a/commands.js b/commands.js index c1656d051c..e3e56b9b7a 100644 --- a/commands.js +++ b/commands.js @@ -1842,8 +1842,8 @@ exports.commands = { let bracketIndex = line.indexOf(']'); let parenIndex = line.indexOf(')'); if (bracketIndex < 0) return Tools.escapeHTML(line); - let time = line.slice(1, bracketIndex); - let timestamp = new Date(time).format('{yyyy}-{MM}-{dd} {hh}:{mm}{tt}'); + const time = line.slice(1, bracketIndex); + let timestamp = Tools.toTimeStamp(new Date(time), {hour12: true}); parenIndex = line.indexOf(')'); let roomid = line.slice(bracketIndex + 3, parenIndex); if (!hideIps && Config.modloglink) { diff --git a/loginserver.js b/loginserver.js index d1d3d2a3c2..8a086dc76a 100644 --- a/loginserver.js +++ b/loginserver.js @@ -142,7 +142,11 @@ class LoginServerInstance { }; let req = null; - let onReqError = (error => { + + let hadError = false; + let onReqError = error => { + if (hadError) return; + hadError = true; if (this.requestTimeoutTimer) { clearTimeout(this.requestTimeoutTimer); this.requestTimeoutTimer = null; @@ -152,7 +156,7 @@ class LoginServerInstance { setImmediate(requestCallbacks[i], null, null, error); } this.requestEnd(error); - }).once(); + }; req = http.request(requestOptions, res => { if (this.requestTimeoutTimer) { @@ -166,7 +170,10 @@ class LoginServerInstance { buffer += chunk; }); - let endReq = (() => { + let requestEnded = false; + let endReq = () => { + if (requestEnded) return; + requestEnded = true; if (this.requestTimeoutTimer) { clearTimeout(this.requestTimeoutTimer); this.requestTimeoutTimer = null; @@ -181,7 +188,7 @@ class LoginServerInstance { } } this.requestEnd(); - }).once(); + }; res.on('end', endReq); res.on('close', endReq); diff --git a/rooms.js b/rooms.js index 4cbe2f33e5..6a76ad4df5 100644 --- a/rooms.js +++ b/rooms.js @@ -1005,9 +1005,10 @@ let BattleRoom = (() => { logData.endType = this.battle.endType; if (!p1rating) logData.ladderError = true; logData.log = BattleRoom.prototype.getLog.call(logData, 3); // replay log (exact damage) - let date = new Date(); - let logfolder = date.format('{yyyy}-{MM}'); - let logsubfolder = date.format('{yyyy}-{MM}-{dd}'); + const date = new Date(); + const logsubfolder = Tools.toTimeStamp(date).split(' ')[0]; + const logfolder = logsubfolder.split('-', 2).join('-'); + let curpath = 'logs/' + logfolder; fs.mkdir(curpath, '0755', () => { let tier = this.format.toLowerCase().replace(/[^a-z0-9]+/g, ''); @@ -1333,7 +1334,7 @@ let ChatRoom = (() => { if (Config.logchat) { this.rollLogFile(true); this.logEntry = function (entry, date) { - let timestamp = (new Date()).format('{HH}:{mm}:{ss} '); + const timestamp = Tools.toTimeStamp(new Date()).split(' ')[1] + ' '; entry = entry.replace(/]* src="data:image\/png;base64,[^">]+"[^>]*>/g, ''); this.logFile.write(timestamp + entry + '\n'); }; @@ -1372,10 +1373,11 @@ let ChatRoom = (() => { let date = new Date(); let basepath = 'logs/chat/' + this.id + '/'; mkdir(basepath, '0755', () => { - let path = date.format('{yyyy}-{MM}'); + const dateString = Tools.toTimeStamp(date).split(' ')[0]; + let path = dateString.split('-', 2).join('-'); mkdir(basepath + path, '0755', () => { if (this.destroyingLog) return; - path += '/' + date.format('{yyyy}-{MM}-{dd}') + '.txt'; + path += '/' + dateString + '.txt'; if (path !== this.logFilename) { this.logFilename = path; if (this.logFile) this.logFile.destroySoon(); @@ -1394,9 +1396,9 @@ let ChatRoom = (() => { } catch (e) {} // OS doesn't support atomic rename } catch (e) {} // OS doesn't support symlinks } - let timestamp = +date; - date.advance('1 hour').reset('minutes').advance('1 second'); - setTimeout(() => this.rollLogFile(), +date - timestamp); + let currentTime = date.getTime(); + let nextHour = new Date(date.setMinutes(60)).setSeconds(1); + setTimeout(() => this.rollLogFile(), nextHour - currentTime); }); }); }; diff --git a/tools.js b/tools.js index ff9fc5a63d..b1865a8555 100644 --- a/tools.js +++ b/tools.js @@ -691,6 +691,19 @@ module.exports = (() => { return ('' + str).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g, '/'); }; + Tools.prototype.toTimeStamp = function (date, options) { + // Return a timestamp in the form {yyyy}-{MM}-{dd} {hh}:{mm}:{ss}. + // Optionally reports hours in mod-12 format. + const isHour12 = options && options.hour12; + let parts = [date.getFullYear(), date.getMonth() + 1, date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds()]; + if (isHour12) { + parts.push(parts[3] >= 12 ? 'pm' : 'am'); + parts[3] = parts[3] % 12 || 12; + } + parts = parts.map(val => val < 10 ? '0' + val : '' + val); + return parts.slice(0, 3).join("-") + " " + parts.slice(3, 6).join(":") + (isHour12 ? " " + parts[6] : ""); + }; + Tools.prototype.toDurationString = function (number) { // TODO: replace by Intl.DurationFormat or equivalent when it becomes available (ECMA-402) // https://github.com/tc39/ecma402/issues/47