diff --git a/config.example.js b/config.example.js new file mode 100644 index 0000000..349aae7 --- /dev/null +++ b/config.example.js @@ -0,0 +1,37 @@ +var config = { + avatars: { + min_size: 1, // for avatars + max_size: 512, // for avatars; too big values might lead to slow response time or DoS + default_size: 160 // for avatars; size to be used when no size given + }, + renders: { + min_scale: 1, // for 3D renders + max_scale: 10, // for 3D renders; too big values might lead to slow response time or DoS + default_scale: 6 // for 3D renders; scale to be used when no scale given + }, + cleaner: { + interval: 1800, // seconds interval: deleting images if disk size at limit + disk_limit: 10240, // min allowed available KB on disk to trigger cleaning + redis_limit: 24576, // max allowed used KB on redis to trigger redis flush + amount: 50000 // amount of avatar (and their helm) files to clean + }, + directories: { + faces_dir: "images/faces/", // directory where faces are kept. should have trailing "/" + helms_dir: "images/helms/", // directory where helms are kept. should have trailing "/" + skins_dir: "images/skins/", // directory where skins are kept. should have trailing "/" + renders_dir: "images/renders/", // Directory where rendered skins are kept. should have trailing "/" + capes_dir: "images/capes/" // directory where capes are kept. should have trailing "/" + }, + caching: { + local_cache_time: 1200, // seconds until we will check if the image changed. should be > 60 to prevent mojang 429 response + browser_cache_time: 3600 // seconds until browser will request image again + }, + server: { + http_timeout: 1000, // ms until connection to mojang is dropped + debug_enabled: false, // enables logging.debug + clusters: 1, // We recommend not using multiple clusters YET, see issue #80 + log_time: true // set to false if you use an external logger that provides timestamps + } +}; + +module.exports = config; \ No newline at end of file diff --git a/config.js b/config.js new file mode 100644 index 0000000..349aae7 --- /dev/null +++ b/config.js @@ -0,0 +1,37 @@ +var config = { + avatars: { + min_size: 1, // for avatars + max_size: 512, // for avatars; too big values might lead to slow response time or DoS + default_size: 160 // for avatars; size to be used when no size given + }, + renders: { + min_scale: 1, // for 3D renders + max_scale: 10, // for 3D renders; too big values might lead to slow response time or DoS + default_scale: 6 // for 3D renders; scale to be used when no scale given + }, + cleaner: { + interval: 1800, // seconds interval: deleting images if disk size at limit + disk_limit: 10240, // min allowed available KB on disk to trigger cleaning + redis_limit: 24576, // max allowed used KB on redis to trigger redis flush + amount: 50000 // amount of avatar (and their helm) files to clean + }, + directories: { + faces_dir: "images/faces/", // directory where faces are kept. should have trailing "/" + helms_dir: "images/helms/", // directory where helms are kept. should have trailing "/" + skins_dir: "images/skins/", // directory where skins are kept. should have trailing "/" + renders_dir: "images/renders/", // Directory where rendered skins are kept. should have trailing "/" + capes_dir: "images/capes/" // directory where capes are kept. should have trailing "/" + }, + caching: { + local_cache_time: 1200, // seconds until we will check if the image changed. should be > 60 to prevent mojang 429 response + browser_cache_time: 3600 // seconds until browser will request image again + }, + server: { + http_timeout: 1000, // ms until connection to mojang is dropped + debug_enabled: false, // enables logging.debug + clusters: 1, // We recommend not using multiple clusters YET, see issue #80 + log_time: true // set to false if you use an external logger that provides timestamps + } +}; + +module.exports = config; \ No newline at end of file diff --git a/lib/cache.js b/lib/cache.js index f681f4c..f5ea38b 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -1,6 +1,6 @@ var logging = require("./logging"); var node_redis = require("redis"); -var config = require("./config"); +var config = require("../config"); var path = require("path"); var url = require("url"); var fs = require("fs"); @@ -40,7 +40,7 @@ function connect_redis() { // the helms file is ignored because we only need 1 file to read/write from function update_file_date(rid, skin_hash) { if (skin_hash) { - var face_path = path.join(__dirname, "..", config.faces_dir, skin_hash + ".png"); + var face_path = path.join(__dirname, "..", config.directories.faces_dir, skin_hash + ".png"); fs.exists(face_path, function(exists) { if (exists) { var date = new Date(); @@ -99,7 +99,7 @@ exp.info = function(callback) { // callback: error exp.update_timestamp = function(rid, userId, hash, temp, callback) { logging.debug(rid, "updating cache timestamp"); - var sub = temp ? (config.local_cache_time - 60) : 0; + var sub = temp ? (config.caching.local_cache_time - 60) : 0; var time = Date.now() - sub; // store userId in lower case if not null userId = userId && userId.toLowerCase(); diff --git a/lib/cleaner.js b/lib/cleaner.js index 8c425fb..1d0c249 100644 --- a/lib/cleaner.js +++ b/lib/cleaner.js @@ -1,5 +1,5 @@ var logging = require("./logging"); -var config = require("./config"); +var config = require("../config"); var cache = require("./cache"); var path = require("path"); var df = require("node-df"); @@ -23,7 +23,7 @@ function should_clean_redis(callback) { logging.debug("used mem:" + info.used_memory); var used = parseInt(info.used_memory) / 1024; logging.log("RedisCleaner:", used + "KB used"); - callback(err, used >= config.cleaning_redis_limit); + callback(err, used >= config.cleaner.redis_limit); } catch(e) { callback(e, false); } @@ -35,7 +35,7 @@ function should_clean_redis(callback) { // callback: error, true|false function should_clean_disk(callback) { df({ - file: path.join(__dirname, "..", config.faces_dir), + file: path.join(__dirname, "..", config.directories.faces_dir), prefixMultiplier: "KiB", isDisplayPrefixMultiplier: false, precision: 2 @@ -45,7 +45,7 @@ function should_clean_disk(callback) { } else { var available = response[0].available; logging.log("DiskCleaner:", available + "KB available"); - callback(err, available < config.cleaning_disk_limit); + callback(err, available < config.cleaner.disk_limit); } }); } @@ -71,13 +71,13 @@ exp.run = function() { logging.error(err); } else if (clean) { logging.warn("DiskCleaner: Disk limit reached! Cleaning images now"); - var facesdir = path.join(__dirname, "..", config.faces_dir); - var helmdir = path.join(__dirname, "..", config.helms_dir); - var renderdir = path.join(__dirname, "..", config.renders_dir); - var skindir = path.join(__dirname, "..", config.skins_dir); + var facesdir = path.join(__dirname, "..", config.directories.faces_dir); + var helmdir = path.join(__dirname, "..", config.directories.helms_dir); + var renderdir = path.join(__dirname, "..", config.directories.renders_dir); + var skindir = path.join(__dirname, "..", config.directories.skins_dir); fs.readdir(facesdir, function (readerr, files) { if (!readerr) { - for (var i = 0, l = Math.min(files.length, config.cleaning_amount); i < l; i++) { + for (var i = 0, l = Math.min(files.length, config.cleaner.amount); i < l; i++) { var filename = files[i]; if (filename[0] !== ".") { fs.unlink(path.join(facesdir, filename), nil); @@ -89,7 +89,7 @@ exp.run = function() { }); fs.readdir(renderdir, function (readerr, files) { if (!readerr) { - for (var j = 0, l = Math.min(files.length, config.cleaning_amount); j < l; j++) { + for (var j = 0, l = Math.min(files.length, config.cleaner.amount); j < l; j++) { var filename = files[j]; if (filename[0] !== ".") { fs.unlink(renderdir + filename, nil); diff --git a/lib/config.example.js b/lib/config.example.js deleted file mode 100644 index a0be444..0000000 --- a/lib/config.example.js +++ /dev/null @@ -1,25 +0,0 @@ -var config = { - min_size: 1, // for avatars - max_size: 512, // for avatars; too big values might lead to slow response time or DoS - default_size: 160, // for avatars; size to be used when no size given - min_scale: 1, // for 3D renders - max_scale: 10, // for 3D renders; too big values might lead to slow response time or DoS - default_scale: 6, // for 3D renders; scale to be used when no scale given - local_cache_time: 1200, // seconds until we will check if the image changed. should be > 60 to prevent mojang 429 response - browser_cache_time: 3600, // seconds until browser will request image again - cleaning_interval: 1800, // seconds interval: deleting images if disk size at limit - cleaning_disk_limit: 10240, // min allowed available KB on disk to trigger cleaning - cleaning_redis_limit: 24576, // max allowed used KB on redis to trigger redis flush - cleaning_amount: 50000, // amount of avatar (and their helm) files to clean - http_timeout: 1000, // ms until connection to mojang is dropped - debug_enabled: false, // enables logging.debug - faces_dir: "images/faces/", // directory where faces are kept. should have trailing "/" - helms_dir: "images/helms/", // directory where helms are kept. should have trailing "/" - skins_dir: "images/skins/", // directory where skins are kept. should have trailing "/" - renders_dir: "images/renders/", // Directory where rendered skins are kept. should have trailing "/" - capes_dir: "images/capes/", // directory where capes are kept. should have trailing "/" - clusters: 1, // We recommend not using multiple clusters YET, see issue #80 - log_time: true, // set to false if you use an external logger that provides timestamps -}; - -module.exports = config; \ No newline at end of file diff --git a/lib/helpers.js b/lib/helpers.js index 73a5967..9a0e577 100644 --- a/lib/helpers.js +++ b/lib/helpers.js @@ -1,7 +1,7 @@ var networking = require("./networking"); var logging = require("./logging"); var renders = require("./renders"); -var config = require("./config"); +var config = require("../config"); var cache = require("./cache"); var skins = require("./skins"); var path = require("path"); @@ -30,9 +30,9 @@ function store_skin(rid, userId, profile, cache_details, callback) { }); } else { logging.log(rid, "new skin hash:", skin_hash); - var facepath = path.join(__dirname, "..", config.faces_dir, skin_hash + ".png"); - var helmpath = path.join(__dirname, "..", config.helms_dir, skin_hash + ".png"); - var skinpath = path.join(__dirname, "..", config.skins_dir, skin_hash + ".png"); + var facepath = path.join(__dirname, "..", config.directories.faces_dir, skin_hash + ".png"); + var helmpath = path.join(__dirname, "..", config.directories.helms_dir, skin_hash + ".png"); + var skinpath = path.join(__dirname, "..", config.directories.skins_dir, skin_hash + ".png"); fs.exists(facepath, function(exists) { if (exists) { logging.log(rid, "skin already exists, not downloading"); @@ -87,7 +87,7 @@ function store_cape(rid, userId, profile, cache_details, callback) { }); } else { logging.log(rid, "new cape hash:", cape_hash); - var capepath = path.join(__dirname, "..", config.capes_dir, cape_hash + ".png"); + var capepath = path.join(__dirname, "..", config.directories.capes_dir, cape_hash + ".png"); fs.exists(capepath, function(exists) { if (exists) { logging.log(rid, "cape already exists, not downloading"); @@ -223,7 +223,7 @@ exp.get_image_hash = function(rid, userId, type, callback) { if (err) { callback(err, -1, null); } else { - if (cache_details && cache_details[type] !== undefined && cache_details.time + config.local_cache_time * 1000 >= Date.now()) { + if (cache_details && cache_details[type] !== undefined && cache_details.time + config.caching.local_cache_time * 1000 >= Date.now()) { // use cached image logging.log(rid, "userId cached & recently updated"); callback(null, (cached_hash ? 1 : 0), cached_hash); @@ -261,8 +261,8 @@ exp.get_image_hash = function(rid, userId, type, callback) { exp.get_avatar = function(rid, userId, helm, size, callback) { exp.get_image_hash(rid, userId, "skin", function(err, status, skin_hash) { if (skin_hash) { - var facepath = path.join(__dirname, "..", config.faces_dir, skin_hash + ".png"); - var helmpath = path.join(__dirname, "..", config.helms_dir, skin_hash + ".png"); + var facepath = path.join(__dirname, "..", config.directories.faces_dir, skin_hash + ".png"); + var helmpath = path.join(__dirname, "..", config.directories.helms_dir, skin_hash + ".png"); var filepath = facepath; fs.exists(helmpath, function(exists) { if (helm && exists) { @@ -288,7 +288,7 @@ exp.get_avatar = function(rid, userId, helm, size, callback) { exp.get_skin = function(rid, userId, callback) { exp.get_image_hash(rid, userId, "skin", function(err, status, skin_hash) { if (skin_hash) { - var skinpath = path.join(__dirname, "..", config.skins_dir, skin_hash + ".png"); + var skinpath = path.join(__dirname, "..", config.directories.skins_dir, skin_hash + ".png"); fs.exists(skinpath, function(exists) { if (exists) { logging.log(rid, "skin already exists, not downloading"); @@ -323,7 +323,7 @@ exp.get_render = function(rid, userId, scale, helm, body, callback) { callback(err, status, skin_hash, null); return; } - var renderpath = path.join(__dirname, "..", config.renders_dir, [skin_hash, scale, get_type(helm, body)].join("-") + ".png"); + var renderpath = path.join(__dirname, "..", config.directories.renders_dir, [skin_hash, scale, get_type(helm, body)].join("-") + ".png"); fs.exists(renderpath, function(exists) { if (exists) { renders.open_render(rid, renderpath, function(render_err, rendered_img) { @@ -362,7 +362,7 @@ exp.get_cape = function(rid, userId, callback) { callback(err, null, status, null); return; } - var capepath = path.join(__dirname, "..", config.capes_dir, cape_hash + ".png"); + var capepath = path.join(__dirname, "..", config.directories.capes_dir, cape_hash + ".png"); fs.exists(capepath, function(exists) { if (exists) { logging.log(rid, "cape already exists, not downloading"); diff --git a/lib/logging.js b/lib/logging.js index fa8ece0..b39844f 100644 --- a/lib/logging.js +++ b/lib/logging.js @@ -1,5 +1,5 @@ var cluster = require("cluster"); -var config = require("./config"); +var config = require("../config"); var exp = {}; @@ -17,7 +17,7 @@ function join_args(args) { // the timestamp can be disabled in the config function log(level, args, logger) { logger = logger || console.log; - var time = config.log_time ? new Date().toISOString() + " " : ""; + var time = config.server.log_time ? new Date().toISOString() + " " : ""; var clid = (cluster.worker && cluster.worker.id || "M"); var lines = join_args(args).split("\n"); for (var i = 0, l = lines.length; i < l; i++) { @@ -34,7 +34,7 @@ exp.warn = function() { exp.error = function() { log("ERROR", arguments, console.error); }; -if (config.debug_enabled || process.env.DEBUG === "true") { +if (config.server.debug_enabled || process.env.DEBUG === "true") { exp.debug = function() { log("DEBUG", arguments); }; diff --git a/lib/networking.js b/lib/networking.js index 31c506d..4dc465b 100644 --- a/lib/networking.js +++ b/lib/networking.js @@ -1,7 +1,7 @@ var http_code = require("http").STATUS_CODES; var logging = require("./logging"); var request = require("request"); -var config = require("./config"); +var config = require("../config"); var skins = require("./skins"); var session_url = "https://sessionserver.mojang.com/session/minecraft/profile/"; @@ -67,7 +67,7 @@ exp.get_from_options = function(rid, url, options, callback) { headers: { "User-Agent": "https://crafatar.com" }, - timeout: config.http_timeout, + timeout: config.server.http_timeout, followRedirect: false, encoding: (options.encoding || null), }, function(error, response, body) { diff --git a/lib/response.js b/lib/response.js index 75a6967..5928fc1 100644 --- a/lib/response.js +++ b/lib/response.js @@ -1,5 +1,5 @@ var logging = require("./logging"); -var config = require("./config"); +var config = require("../config"); var crc = require("crc").crc32; var human_status = { @@ -39,7 +39,7 @@ module.exports = function(request, response, result) { // These headers are the same for every response var headers = { "Content-Type": (result.body && result.type) || "text/plain", - "Cache-Control": "max-age=" + config.browser_cache_time + ", public", + "Cache-Control": "max-age=" + config.caching.browser_cache_time + ", public", "Response-Time": Date.now() - request.start, "X-Request-ID": request.id, "Access-Control-Allow-Origin": "*" diff --git a/lib/routes/avatars.js b/lib/routes/avatars.js index b0dfa19..5dad944 100644 --- a/lib/routes/avatars.js +++ b/lib/routes/avatars.js @@ -1,6 +1,6 @@ var logging = require("../logging"); var helpers = require("../helpers"); -var config = require("../config"); +var config = require("../../config"); var skins = require("../skins"); var cache = require("../cache"); var path = require("path"); @@ -45,7 +45,7 @@ function handle_default(img_status, userId, size, def, req, err, callback) { // GET avatar request module.exports = function(req, callback) { var userId = (req.url.path_list[1] || "").split(".")[0]; - var size = parseInt(req.url.query.size) || config.default_size; + var size = parseInt(req.url.query.size) || config.avatars.default_size; var def = req.url.query.default; var helm = req.url.query.hasOwnProperty("helm"); @@ -59,7 +59,7 @@ module.exports = function(req, callback) { } // Prevent app from crashing/freezing - if (size < config.min_size || size > config.max_size) { + if (size < config.avatars.min_size || size > config.avatars.max_size) { // "Unprocessable Entity", valid request, but semantically erroneous: // https://tools.ietf.org/html/rfc4918#page-78 callback({ diff --git a/lib/routes/index.js b/lib/routes/index.js index 7ffbcb2..c3d76cf 100644 --- a/lib/routes/index.js +++ b/lib/routes/index.js @@ -1,4 +1,4 @@ -var config = require("../config"); +var config = require("../../config"); var path = require("path"); var jade = require("jade"); diff --git a/lib/routes/renders.js b/lib/routes/renders.js index fe332ca..819e976 100644 --- a/lib/routes/renders.js +++ b/lib/routes/renders.js @@ -1,7 +1,7 @@ var logging = require("../logging"); var helpers = require("../helpers"); var renders = require("../renders"); -var config = require("../config"); +var config = require("../../config"); var cache = require("../cache"); var skins = require("../skins"); var path = require("path"); @@ -9,8 +9,6 @@ var fs = require("fs"); // valid types: head, body // helmet is query param -// TODO: The Type logic should be two separate GET functions once response methods are extracted - function handle_default(rid, scale, helm, body, img_status, userId, size, def, req, err, callback) { def = def || skins.default_skin(userId); if (def !== "steve" && def !== "alex") { @@ -57,7 +55,7 @@ module.exports = function(req, callback) { var body = raw_type === "body"; var userId = (req.url.path_list[2] || "").split(".")[0]; var def = req.url.query.default; - var scale = parseInt(req.url.query.scale) || config.default_scale; + var scale = parseInt(req.url.query.scale) || config.renders.default_scale; var helm = req.url.query.hasOwnProperty("helm"); // check for extra paths @@ -78,7 +76,7 @@ module.exports = function(req, callback) { return; } - if (scale < config.min_scale || scale > config.max_scale) { + if (scale < config.renders.min_scale || scale > config.renders.max_scale) { callback({ status: -2, body: "Invalid Scale" diff --git a/lib/server.js b/lib/server.js index c7b4679..50f2c93 100644 --- a/lib/server.js +++ b/lib/server.js @@ -3,7 +3,7 @@ var querystring = require("querystring"); var response = require("./response"); var toobusy = require("toobusy-js"); var logging = require("./logging"); -var config = require("./config"); +var config = require("../config"); var http = require("http"); var mime = require("mime"); var path = require("path"); @@ -116,7 +116,7 @@ function requestHandler(req, res) { res.writeHead(500, { "Content-Type": "text/plain" }); - res.end(config.debug_enabled ? error : "Internal Server Error"); + res.end(config.server.debug_enabled ? error : "Internal Server Error"); } } else { res.writeHead(405, { diff --git a/lib/views/index.jade b/lib/views/index.jade index 7fe22ac..6fd0679 100644 --- a/lib/views/index.jade +++ b/lib/views/index.jade @@ -56,8 +56,8 @@ block content tr td size td integer - td #{config.default_size} - td The size of the image in pixels, #{config.min_size} - #{config.max_size}. + td #{config.avatars.default_size} + td The size of the image in pixels, #{config.avatars.min_size} - #{config.avatars.max_size}. tr td default td string @@ -140,8 +140,8 @@ block content tr td scale td integer - td #{config.default_scale}. The actual size differs between the type of render. - td The scale factor of the image #{config.min_scale} - #{config.max_scale}. + td #{config.renders.default_scale}. The actual size differs between the type of render. + td The scale factor of the image #{config.renders.min_scale} - #{config.renders.max_scale}. tr td helm td null @@ -324,8 +324,8 @@ block content a(href="#meta-about-caching") h3 About Caching p - | Crafatar caches skins for #{config.local_cache_time/60} minutes before checking for skin changes.
- | Images are cached in your browser for #{config.browser_cache_time/60} minutes until a new request to Crafatar is made.
+ | Crafatar caches skins for #{config.caching.local_cache_time/60} minutes before checking for skin changes.
+ | Images are cached in your browser for #{config.caching.browser_cache_time/60} minutes until a new request to Crafatar is made.
| When you changed your skin you can try clearing your browser cache to see the change faster. diff --git a/test/test.js b/test/test.js index eef1372..fb27d22 100644 --- a/test/test.js +++ b/test/test.js @@ -5,7 +5,7 @@ var helpers = require("../lib/helpers"); var logging = require("../lib/logging"); var cleaner = require("../lib/cleaner"); var request = require("request"); -var config = require("../lib/config"); +var config = require("../config"); var server = require("../lib/server"); var assert = require("assert"); var skins = require("../lib/skins"); @@ -14,7 +14,7 @@ var crc = require("crc").crc32; var fs = require("fs"); // we don't want tests to fail because of slow internet -config.http_timeout *= 3; +config.server.http_timeout *= 3; // no spam if (process.env.VERBOSE_TEST !== "true") { @@ -67,13 +67,13 @@ var ids = [ describe("Crafatar", function() { // we might have to make 2 HTTP requests - this.timeout(config.http_timeout * 2 + 50); + this.timeout(config.server.http_timeout * 2 + 50); before(function() { cache.get_redis().flushall(); // cause I don't know how big hard drives are these days - config.cleaning_disk_limit = Infinity; - config.cleaning_redis_limit = Infinity; + config.cleaner.disk_limit = Infinity; + config.cleaner.redis_limit = Infinity; cleaner.run(); }); @@ -170,29 +170,29 @@ describe("Crafatar", function() { }); describe("Errors", function() { it("should time out on uuid info download", function(done) { - var original_timeout = config.http_timeout; - config.http_timeout = 1; + var original_timeout = config.server.http_timeout; + config.server.http_timeout = 1; networking.get_profile(rid, "069a79f444e94726a5befca90e38aaf5", function(err, profile) { assert.strictEqual(err.code, "ETIMEDOUT"); - config.http_timeout = original_timeout; + config.server.http_timeout = original_timeout; done(); }); }); it("should time out on username info download", function(done) { - var original_timeout = config.http_timeout; - config.http_timeout = 1; + var original_timeout = config.server.http_timeout; + config.server.http_timeout = 1; networking.get_username_url(rid, "jomo", 0, function(err, url) { assert.strictEqual(err.code, "ETIMEDOUT"); - config.http_timeout = original_timeout; + config.server.http_timeout = original_timeout; done(); }); }); it("should time out on skin download", function(done) { var original_timeout = config.http_timeout; - config.http_timeout = 1; + config.server.http_timeout = 1; networking.get_from(rid, "http://textures.minecraft.net/texture/477be35554684c28bdeee4cf11c591d3c88afb77e0b98da893fd7bc318c65184", function(body, res, error) { assert.strictEqual(error.code, "ETIMEDOUT"); - config.http_timeout = original_timeout; + config.server.http_timeout = original_timeout; done(); }); }); @@ -227,7 +227,7 @@ describe("Crafatar", function() { assert("" + res.headers["response-time"]); assert(res.headers["x-request-id"]); assert.equal(res.headers["access-control-allow-origin"], "*"); - assert.equal(res.headers["cache-control"], "max-age=" + config.browser_cache_time + ", public"); + assert.equal(res.headers["cache-control"], "max-age=" + config.caching.browser_cache_time + ", public"); } // throws Exception when +url+ is requested with +etag+ @@ -352,6 +352,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [862751081, 809395677] }, + "avatar with non-existent username defaulting to userId": { + url: "http://localhost:3000/avatars/0?size=16&default=jeb_", + crc32: 0, + redirect: "/avatars/jeb_?size=16" + }, "avatar with non-existent username defaulting to url": { url: "http://localhost:3000/avatars/0?size=16&default=http://example.com", crc32: 0, @@ -372,6 +377,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [862751081, 809395677] }, + "helm avatar with non-existent username defaulting to userId": { + url: "http://localhost:3000/avatars/0?size=16&helm&default=jeb_", + crc32: 0, + redirect: "/avatars/jeb_?size=16&helm=" + }, "helm avatar with non-existent username defaulting to url": { url: "http://localhost:3000/avatars/0?size=16&helm&default=http://example.com", crc32: 0, @@ -392,6 +402,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [862751081, 809395677] }, + "avatar with non-existent uuid defaulting to userId": { + url: "http://localhost:3000/avatars/00000000000000000000000000000000?size=16&default=jeb_", + crc32: 0, + redirect: "/avatars/jeb_?size=16" + }, "avatar with non-existent uuid defaulting to url": { url: "http://localhost:3000/avatars/00000000000000000000000000000000?size=16&default=http://example.com", crc32: 0, @@ -412,6 +427,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [862751081, 809395677] }, + "helm avatar with non-existent uuid defaulting to userId": { + url: "http://localhost:3000/avatars/00000000000000000000000000000000?size=16&default=jeb_", + crc32: 0, + redirect: "/avatars/jeb_?size=16" + }, "helm avatar with non-existent uuid defaulting to url": { url: "http://localhost:3000/avatars/00000000000000000000000000000000?size=16&helm&default=http://example.com", crc32: 0, @@ -460,6 +480,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: 2298915739 }, + "skin with non-existent username defaulting to userId": { + url: "http://localhost:3000/skins/0?size=16&default=jeb_", + crc32: 0, + redirect: "/skins/jeb_?size=16" + }, "skin with non-existent username defaulting to url": { url: "http://localhost:3000/skins/0?default=http://example.com", crc32: 0, @@ -480,11 +505,18 @@ describe("Crafatar", function() { etag: '"alex"', crc32: 2298915739 }, + "skin with non-existent uuid defaulting to userId": { + url: "http://localhost:3000/skins/00000000000000000000000000000000?size=16&default=jeb_", + crc32: 0, + redirect: "/skins/jeb_?size=16" + }, "skin with non-existent uuid defaulting to url": { url: "http://localhost:3000/skins/00000000000000000000000000000000?default=http://example.com", crc32: 0, redirect: "http://example.com" }, + + "head render with existing username": { url: "http://localhost:3000/renders/head/jeb_?scale=2", etag: '"a846b82963"', @@ -500,6 +532,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [1240086237, 1108800327] }, + "head render with non-existent useranme defaulting to userId": { + url: "http://localhost:3000/avatars/0?scale=2&default=jeb_", + crc32: 0, + redirect: "/renders/head/jeb_?scale=2" + }, "head render with non-existent username defaulting to url": { url: "http://localhost:3000/renders/head/0?scale=2&default=http://example.com", crc32: 0, @@ -520,6 +557,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [2963161105, 1769904825] }, + "helm head render with non-existent username defaulting to userId": { + url: "http://localhost:3000/renders/head/0?scale=2&helm&default=jeb_", + crc32: 0, + redirect: "/renders/head/jeb_?scale=2&helm=" + }, "helm head render with non-existent username defaulting to url": { url: "http://localhost:3000/renders/head/0?scale=2&helm&default=http://example.com", crc32: 0, @@ -540,6 +582,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [1240086237, 1108800327] }, + "head render with non-existent uuid defaulting to userId": { + url: "http://localhost:3000/renders/head/00000000000000000000000000000000?scale=2&default=jeb_", + crc32: 0, + redirect: "/renders/head/jeb_?scale=2" + }, "head render with non-existent uuid defaulting to url": { url: "http://localhost:3000/renders/head/00000000000000000000000000000000?scale=2&default=http://example.com", crc32: 0, @@ -560,6 +607,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [2963161105, 1769904825] }, + "helm head with non-existent uuid defaulting to userId": { + url: "http://localhost:3000/renders/head/00000000000000000000000000000000?scale=2&helm&default=jeb_", + crc32: 0, + redirect: "/renders/head/jeb_?scale=2&helm=" + }, "helm head render with non-existent uuid defaulting to url": { url: "http://localhost:3000/renders/head/00000000000000000000000000000000?scale=2&helm&default=http://example.com", crc32: 0, @@ -580,6 +632,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [407932087, 2516216042] }, + "body render with non-existent username defaulting to userId": { + url: "http://localhost:3000/renders/body/0?scale=2&default=jeb_", + crc32: 0, + redirect: "/renders/body/jeb_?scale=2" + }, "body render with non-existent username defaulting to url": { url: "http://localhost:3000/renders/body/0?scale=2&default=http://example.com", crc32: 0, @@ -600,6 +657,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [737759773, 66512449] }, + "helm body render with non-existent username defaulting to userId": { + url: "http://localhost:3000/renders/body/0?scale=2&helm&default=jeb_", + crc32: 0, + redirect: "/renders/body/jeb_?scale=2&helm=" + }, "helm body render with non-existent username defaulting to url": { url: "http://localhost:3000/renders/body/0?scale=2&helm&default=http://example.com", crc32: 0, @@ -620,6 +682,11 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [407932087, 2516216042] }, + "body render with non-existent uuid defaulting to userId": { + url: "http://localhost:3000/renders/body/0?scale=2&default=jeb_", + crc32: 0, + redirect: "/renders/body/jeb_?scale=2" + }, "body render with non-existent uuid defaulting to url": { url: "http://localhost:3000/renders/body/00000000000000000000000000000000?scale=2&default=http://example.com", crc32: 0, @@ -640,11 +707,6 @@ describe("Crafatar", function() { etag: '"alex"', crc32: [737759773, 66512449] }, - "helm body render with non-existent uuid defaulting to userId": { - url: "http://localhost:3000/renders/body/00000000000000000000000000000000?scale=2&helm&default=alex", - etag: '"alex"', - crc32: [737759773, 66512449] - }, "helm body render with non-existent uuid defaulting to url": { url: "http://localhost:3000/renders/body/00000000000000000000000000000000?scale=2&helm&default=http://example.com", crc32: 0, @@ -696,7 +758,7 @@ describe("Crafatar", function() { } it("should return a 422 (invalid size)", function(done) { - var size = config.max_size + 1; + var size = config.avatars.max_size + 1; request.get("http://localhost:3000/avatars/Jake_0?size=" + size, function(error, res, body) { assert.ifError(error); assert.strictEqual(res.statusCode, 422); @@ -705,7 +767,7 @@ describe("Crafatar", function() { }); it("should return a 422 (invalid scale)", function(done) { - var scale = config.max_scale + 1; + var scale = config.renders.max_scale + 1; request.get("http://localhost:3000/renders/head/Jake_0?scale=" + scale, function(error, res, body) { assert.ifError(error); assert.strictEqual(res.statusCode, 422); @@ -833,12 +895,12 @@ describe("Crafatar", function() { console.log("can't run 'checked' test due to Mojang's rate limits :("); } else { it("should be checked", function(done) { - var original_cache_time = config.local_cache_time; - config.local_cache_time = 0; + var original_cache_time = config.caching.local_cache_time; + config.caching.local_cache_time = 0; helpers.get_avatar(rid, id, false, 160, function(err, status, image) { assert.ifError(err); assert.strictEqual(status, 3); - config.local_cache_time = original_cache_time; + config.caching.local_cache_time = original_cache_time; done(); }); }); diff --git a/www.js b/www.js index 7690356..981c14b 100644 --- a/www.js +++ b/www.js @@ -1,6 +1,6 @@ var logging = require("./lib/logging"); var cleaner = require("./lib/cleaner"); -var config = require("./lib/config"); +var config = require("./config"); var cluster = require("cluster"); process.on("uncaughtException", function (err) { @@ -8,8 +8,8 @@ process.on("uncaughtException", function (err) { }); if (cluster.isMaster) { - var cores = config.clusters || require("os").cpus().length; - logging.log("Starting", cores + " workers"); + var cores = config.server.clusters || require("os").cpus().length; + logging.log("Starting", cores + " worker" + (cores > 1 ? "s" : "")); for (var i = 0; i < cores; i++) { cluster.fork(); } @@ -19,7 +19,7 @@ if (cluster.isMaster) { setTimeout(cluster.fork, 100); }); - setInterval(cleaner.run, config.cleaning_interval * 1000); + setInterval(cleaner.run, config.cleaner.interval * 1000); } else { require("./lib/server.js").boot(); } \ No newline at end of file