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