renders.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. var logging = require("../modules/logging");
  2. var helpers = require("../modules/helpers");
  3. var config = require("../modules/config");
  4. var cache = require("../modules/cache");
  5. var skins = require("../modules/skins");
  6. var renders = require("../modules/renders");
  7. var fs = require("fs");
  8. var human_status = {
  9. 0: "none",
  10. 1: "cached",
  11. 2: "downloaded",
  12. 3: "checked",
  13. "-1": "error"
  14. };
  15. // valid types: head, body
  16. // helmet is query param
  17. // TODO: The Type logic should be two separate GET functions once response methods are extracted
  18. // GET render request
  19. module.exports = function(req, res) {
  20. var start = new Date();
  21. var raw_type = (req.url.path_list[2] || "");
  22. var rid = req.id;
  23. // validate type
  24. if (raw_type !== "body" && raw_type !== "head") {
  25. res.writeHead(422, {
  26. "Content-Type": "text/plain",
  27. "Response-Time": new Date() - start
  28. });
  29. res.end("Invalid Render Type");
  30. return;
  31. }
  32. var body = raw_type === "body";
  33. var userId = (req.url.path_list[3] || "").split(".")[0];
  34. var def = req.url.query.default;
  35. var scale = parseInt(req.url.query.scale) || config.default_scale;
  36. var helm = req.url.query.hasOwnProperty("helm");
  37. var etag = null;
  38. if (scale < config.min_scale || scale > config.max_scale) {
  39. res.writeHead(422, {
  40. "Content-Type": "text/plain",
  41. "Response-Time": new Date() - start
  42. });
  43. res.end("422 Invalid Scale");
  44. return;
  45. } else if (!helpers.id_valid(userId)) {
  46. res.writeHead(422, {
  47. "Content-Type": "text/plain",
  48. "Response-Time": new Date() - start
  49. });
  50. res.end("422 Invalid ID");
  51. return;
  52. }
  53. // strip dashes
  54. userId = userId.replace(/-/g, "");
  55. logging.log(rid + "userId: " + userId);
  56. try {
  57. helpers.get_render(rid, userId, scale, helm, body, function(err, status, hash, image) {
  58. logging.log(rid + "storage type: " + human_status[status]);
  59. if (err) {
  60. logging.error(rid + err);
  61. if (err.code === "ENOENT") {
  62. // no such file
  63. cache.remove_hash(rid, userId);
  64. }
  65. }
  66. etag = hash && hash.substr(0, 32) || "none";
  67. var matches = req.headers["if-none-match"] === '"' + etag + '"';
  68. if (image) {
  69. var http_status = 200;
  70. if (matches) {
  71. http_status = 304;
  72. } else if (err) {
  73. http_status = 503;
  74. }
  75. logging.debug(rid + "etag: " + req.headers["if-none-match"]);
  76. logging.debug(rid + "matches: " + matches);
  77. sendimage(rid, http_status, status, image);
  78. } else {
  79. logging.log(rid + "image not found, using default.");
  80. handle_default(rid, 404, status, userId);
  81. }
  82. });
  83. } catch(e) {
  84. logging.error(rid + "error: " + e.stack);
  85. handle_default(rid, 500, -1, userId);
  86. }
  87. // default alex/steve images can be rendered, but
  88. // custom images will not be
  89. function handle_default(rid, http_status, img_status, userId) {
  90. if (def && def !== "steve" && def !== "alex") {
  91. logging.log(rid + "status: 301");
  92. res.writeHead(301, {
  93. "Cache-Control": "max-age=" + config.browser_cache_time + ", public",
  94. "Response-Time": new Date() - start,
  95. "X-Storage-Type": human_status[img_status],
  96. "X-Request-ID": rid,
  97. "Access-Control-Allow-Origin": "*",
  98. "Location": def
  99. });
  100. res.end();
  101. } else {
  102. def = def || skins.default_skin(userId);
  103. fs.readFile("public/images/" + def + "_skin.png", function (err, buf) {
  104. if (err) {
  105. // errored while loading the default image, continuing with null image
  106. logging.error(rid + "error loading default render image: " + err);
  107. }
  108. // we render the default skins, but not custom images
  109. renders.draw_model(rid, buf, scale, helm, body, function(err, def_img) {
  110. if (err) {
  111. logging.error(rid + "error while rendering default image: " + err);
  112. }
  113. sendimage(rid, http_status, img_status, def_img);
  114. });
  115. });
  116. }
  117. }
  118. function sendimage(rid, http_status, img_status, image) {
  119. logging.log(rid + "status: " + http_status);
  120. res.writeHead(http_status, {
  121. "Content-Type": "image/png",
  122. "Cache-Control": "max-age=" + config.browser_cache_time + ", public",
  123. "Response-Time": new Date() - start,
  124. "X-Storage-Type": human_status[img_status],
  125. "X-Request-ID": rid,
  126. "Access-Control-Allow-Origin": "*",
  127. "Etag": '"' + etag + '"'
  128. });
  129. res.end(http_status === 304 ? null : image);
  130. }
  131. };