2
0

renders.js 4.4 KB

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