renders.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. var logging = require("../logging");
  2. var helpers = require("../helpers");
  3. var config = require("../config");
  4. var cache = require("../cache");
  5. var skins = require("../skins");
  6. var renders = require("../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. function sendimage(rid, http_status, img_status, image) {
  39. logging.log(rid, "status:", http_status);
  40. res.writeHead(http_status, {
  41. "Content-Type": "image/png",
  42. "Cache-Control": "max-age=" + config.browser_cache_time + ", public",
  43. "Response-Time": new Date() - start,
  44. "X-Storage-Type": human_status[img_status],
  45. "X-Request-ID": rid,
  46. "Access-Control-Allow-Origin": "*",
  47. "Etag": '"' + etag + '"'
  48. });
  49. res.end(http_status === 304 ? null : image);
  50. }
  51. // default alex/steve images can be rendered, but
  52. // custom images will not be
  53. function handle_default(rid, http_status, img_status, userId) {
  54. if (def && def !== "steve" && def !== "alex") {
  55. logging.log(rid, "status: 301");
  56. res.writeHead(301, {
  57. "Cache-Control": "max-age=" + config.browser_cache_time + ", public",
  58. "Response-Time": new Date() - start,
  59. "X-Storage-Type": human_status[img_status],
  60. "X-Request-ID": rid,
  61. "Access-Control-Allow-Origin": "*",
  62. "Location": def
  63. });
  64. res.end();
  65. } else {
  66. def = def || skins.default_skin(userId);
  67. fs.readFile("public/images/" + def + "_skin.png", function (err, buf) {
  68. if (err) {
  69. // errored while loading the default image, continuing with null image
  70. logging.error(rid, "error loading default render image:", err);
  71. }
  72. // we render the default skins, but not custom images
  73. renders.draw_model(rid, buf, scale, helm, body, function(render_err, def_img) {
  74. if (render_err) {
  75. logging.error(rid, "error while rendering default image:", render_err);
  76. }
  77. sendimage(rid, http_status, img_status, def_img);
  78. });
  79. });
  80. }
  81. }
  82. if (scale < config.min_scale || scale > config.max_scale) {
  83. res.writeHead(422, {
  84. "Content-Type": "text/plain",
  85. "Response-Time": new Date() - start
  86. });
  87. res.end("422 Invalid Scale");
  88. return;
  89. } else if (!helpers.id_valid(userId)) {
  90. res.writeHead(422, {
  91. "Content-Type": "text/plain",
  92. "Response-Time": new Date() - start
  93. });
  94. res.end("422 Invalid ID");
  95. return;
  96. }
  97. // strip dashes
  98. userId = userId.replace(/-/g, "");
  99. logging.log(rid, "userId:", userId);
  100. try {
  101. helpers.get_render(rid, userId, scale, helm, body, function(err, status, hash, image) {
  102. logging.log(rid, "storage type:", human_status[status]);
  103. if (err) {
  104. logging.error(rid, err);
  105. if (err.code === "ENOENT") {
  106. // no such file
  107. cache.remove_hash(rid, userId);
  108. }
  109. }
  110. etag = hash && hash.substr(0, 32) || "none";
  111. var matches = req.headers["if-none-match"] === '"' + etag + '"';
  112. if (image) {
  113. var http_status = 200;
  114. if (err) {
  115. http_status = 503;
  116. }
  117. logging.debug(rid, "etag:", req.headers["if-none-match"]);
  118. logging.debug(rid, "matches:", matches);
  119. sendimage(rid, matches ? 304 : http_status, status, image);
  120. } else {
  121. logging.log(rid, "image not found, using default.");
  122. handle_default(rid, matches ? 304 : 200, status, userId);
  123. }
  124. });
  125. } catch(e) {
  126. logging.error(rid, "error:", e.stack);
  127. handle_default(rid, 500, -1, userId);
  128. }
  129. };