renders.js 4.4 KB

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