Use create-error for better error creation

This commit is contained in:
calzoneman 2015-09-24 23:36:05 -07:00
parent 5ec9c2b029
commit 20dc871303
7 changed files with 46 additions and 38 deletions

View File

@ -14,6 +14,7 @@
"cheerio": "^0.19.0", "cheerio": "^0.19.0",
"compression": "^1.5.2", "compression": "^1.5.2",
"cookie-parser": "^1.4.0", "cookie-parser": "^1.4.0",
"create-error": "^0.3.1",
"csrf": "^3.0.0", "csrf": "^3.0.0",
"cytube-mediaquery": "git://github.com/CyTube/mediaquery", "cytube-mediaquery": "git://github.com/CyTube/mediaquery",
"cytubefilters": "git://github.com/calzoneman/cytubefilters#095b7956", "cytubefilters": "git://github.com/calzoneman/cytubefilters#095b7956",

View File

@ -64,7 +64,9 @@ function initChannelDumper(Server) {
for (var i = 0; i < Server.channels.length; i++) { for (var i = 0; i < Server.channels.length; i++) {
var chan = Server.channels[i]; var chan = Server.channels[i];
if (!chan.dead && chan.users && chan.users.length > 0) { if (!chan.dead && chan.users && chan.users.length > 0) {
chan.saveState(); chan.saveState().catch(err => {
Logger.errlog.log(`Failed to save /r/${chan.name}: ${err.stack}`);
});
} }
} }
}, CHANNEL_SAVE_INTERVAL); }, CHANNEL_SAVE_INTERVAL);

View File

@ -1,6 +1,6 @@
import { FileStore } from './filestore'; import { FileStore } from './filestore';
var CHANNEL_STORE = new FileStore(); const CHANNEL_STORE = new FileStore();
export function load(channelName) { export function load(channelName) {
return CHANNEL_STORE.load(channelName); return CHANNEL_STORE.load(channelName);

View File

@ -2,6 +2,7 @@ import * as Promise from 'bluebird';
import { stat } from 'fs'; import { stat } from 'fs';
import * as fs from 'graceful-fs'; import * as fs from 'graceful-fs';
import path from 'path'; import path from 'path';
import { ChannelStateSizeError } from '../errors';
const readFileAsync = Promise.promisify(fs.readFile); const readFileAsync = Promise.promisify(fs.readFile);
const writeFileAsync = Promise.promisify(fs.writeFile); const writeFileAsync = Promise.promisify(fs.writeFile);
@ -18,7 +19,10 @@ export class FileStore {
const filename = this.filenameForChannel(channelName); const filename = this.filenameForChannel(channelName);
return statAsync(filename).then(stats => { return statAsync(filename).then(stats => {
if (stats.size > SIZE_LIMIT) { if (stats.size > SIZE_LIMIT) {
throw new Error('Channel state file is too large: ' + stats.size); throw new ChannelStateSizeError('Channel state file is too large', {
limit: SIZE_LIMIT,
actual: stats.size
});
} else { } else {
return readFileAsync(filename); return readFileAsync(filename);
} }
@ -34,11 +38,12 @@ export class FileStore {
save(channelName, data) { save(channelName, data) {
const filename = this.filenameForChannel(channelName); const filename = this.filenameForChannel(channelName);
const fileContents = new Buffer(JSON.stringify(data), 'utf8'); const fileContents = new Buffer(JSON.stringify(data), 'utf8');
if (fileContents.length > SIZE_LIMIT) { if (fileContents.length > 0*SIZE_LIMIT) {
let error = new Error('Channel state size is too large'); return Promise.reject(new ChannelStateSizeError(
error.limit = SIZE_LIMIT; 'Channel state size is too large', {
error.size = fileContents.length; limit: SIZE_LIMIT,
return Promise.reject(error); actual: fileContents.length
}));
} }
return writeFileAsync(filename, fileContents); return writeFileAsync(filename, fileContents);

View File

@ -8,10 +8,9 @@ var fs = require("graceful-fs");
var path = require("path"); var path = require("path");
var sio = require("socket.io"); var sio = require("socket.io");
var db = require("../database"); var db = require("../database");
var ChannelStore = require("../channel-storage/channelstore"); import * as ChannelStore from '../channel-storage/channelstore';
var Promise = require("bluebird"); import { ChannelStateSizeError } from '../errors';
import * as Promise from 'bluebird';
const SIZE_LIMIT = 1048576;
/** /**
* Previously, async channel functions were riddled with race conditions due to * Previously, async channel functions were riddled with race conditions due to
@ -180,6 +179,13 @@ Channel.prototype.loadState = function () {
} }
}); });
this.setFlag(Flags.C_READY); this.setFlag(Flags.C_READY);
}).catch(ChannelStateSizeError, err => {
const message = "This channel's state size has exceeded the memory limit " +
"enforced by this server. Please contact an administrator " +
"for assistance.";
Logger.errlog.log(err.stack);
errorLoad(message);
}).catch(err => { }).catch(err => {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
Object.keys(this.modules).forEach(m => { Object.keys(this.modules).forEach(m => {
@ -187,21 +193,14 @@ Channel.prototype.loadState = function () {
}); });
this.setFlag(Flags.C_READY); this.setFlag(Flags.C_READY);
return; return;
}
let message;
if (/Channel state file is too large/.test(err.message)) {
message = "This channel's state size has exceeded the memory limit " +
"enforced by this server. Please contact an administrator " +
"for assistance.";
} else { } else {
message = "An error occurred when loading this channel's data from " + const message = "An error occurred when loading this channel's data from " +
"disk. Please contact an administrator for assistance. " + "disk. Please contact an administrator for assistance. " +
`The error was: ${err}`; `The error was: ${err}`;
}
Logger.errlog.log(err.stack); Logger.errlog.log(err.stack);
errorLoad(message); errorLoad(message);
}
}); });
}; };
@ -220,22 +219,17 @@ Channel.prototype.saveState = function () {
this.modules[m].save(data); this.modules[m].save(data);
}); });
return ChannelStore.save(this.uniqueName, data).catch(err => { return ChannelStore.save(this.uniqueName, data).catch(ChannelStateSizeError, err => {
if (/Channel state size is too large/.test(err.message)) { this.users.forEach(u => {
this.users.forEach(u => { if (u.account.effectiveRank >= 2) {
if (u.account.effectiveRank >= 2) { u.socket.emit("warnLargeChandump", {
u.socket.emit("warnLargeChandump", { limit: err.limit,
limit: err.limit, actual: err.actual
actual: err.size });
}); }
} });
});
Logger.errlog.log(`Not saving ${this.uniqueName} because it exceeds ` + throw err;
"the size limit");
} else {
Logger.errlog.log(`Failed to save ${this.uniqueName}: ${err.stack}`);
}
}); });
}; };

3
src/errors.js Normal file
View File

@ -0,0 +1,3 @@
import createError from 'create-error';
export const ChannelStateSizeError = createError('ChannelStateSizeError');

View File

@ -236,6 +236,9 @@ Server.prototype.shutdown = function () {
}).then(() => { }).then(() => {
Logger.syslog.log("Goodbye"); Logger.syslog.log("Goodbye");
process.exit(0); process.exit(0);
}).catch(err => {
Logger.errlog.log(`Caught error while saving channels: ${err.stack}`);
process.exit(1);
}); });
}; };