renders.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  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. // validate type
  22. if (raw_type != "body" && raw_type != "head") {
  23. res.writeHead(422, {
  24. "Content-Type": "text/plain",
  25. "Response-Time": new Date() - start
  26. });
  27. res.end("Invalid Render Type");
  28. return;
  29. }
  30. var body = raw_type == "body";
  31. var uuid = (req.url.path_list[3] || "").split(".")[0];
  32. var def = req.url.query.default;
  33. var scale = parseInt(req.url.query.scale) || config.default_scale;
  34. var helm = req.url.query.hasOwnProperty("helm");
  35. var etag = null;
  36. if (scale < config.min_scale || scale > config.max_scale) {
  37. res.writeHead(422, {
  38. "Content-Type": "text/plain",
  39. "Response-Time": new Date() - start
  40. });
  41. res.end("422 Invalid Scale");
  42. return;
  43. } else if (!helpers.uuid_valid(uuid)) {
  44. res.writeHead(422, {
  45. "Content-Type": "text/plain",
  46. "Response-Time": new Date() - start
  47. });
  48. res.end("422 Invalid UUID");
  49. return;
  50. }
  51. // strip dashes
  52. uuid = uuid.replace(/-/g, "");
  53. try {
  54. helpers.get_render(uuid, scale, helm, body, function(err, status, hash, image) {
  55. logging.log(uuid + " - " + human_status[status]);
  56. if (err) {
  57. logging.error(uuid + " " + err);
  58. }
  59. etag = hash && hash.substr(0, 32) || "none";
  60. var matches = req.headers["if-none-match"] == '"' + etag + '"';
  61. if (image) {
  62. var http_status = 200;
  63. if (matches) {
  64. http_status = 304;
  65. } else if (err) {
  66. http_status = 503;
  67. }
  68. logging.log("matches: " + matches);
  69. logging.log("Etag: " + req.headers["if-none-match"]);
  70. sendimage(http_status, status, image);
  71. } else {
  72. logging.log("image not found, using default.");
  73. handle_default(404, status);
  74. }
  75. });
  76. } catch(e) {
  77. logging.error(uuid + " error:");
  78. logging.error(e);
  79. handle_default(500, status);
  80. }
  81. // default alex/steve images can be rendered, but
  82. // custom images will not be
  83. function handle_default(http_status, img_status) {
  84. if (def && def != "steve" && def != "alex") {
  85. logging.log("status: 301");
  86. res.writeHead(301, {
  87. "Cache-Control": "max-age=" + config.browser_cache_time + ", public",
  88. "Response-Time": new Date() - start,
  89. "X-Storage-Type": human_status[img_status],
  90. "Access-Control-Allow-Origin": "*",
  91. "Location": def
  92. });
  93. res.end();
  94. } else {
  95. def = def || skins.default_skin(uuid);
  96. fs.readFile("public/images/" + def + "_skin.png", function (err, buf) {
  97. if (err) {
  98. // errored while loading the default image, continuing with null image
  99. logging.error("error loading default render image: " + err);
  100. }
  101. // we render the default skins, but not custom images
  102. renders.draw_model(uuid, buf, scale, helm, body, function(err, def_img) {
  103. if (err) {
  104. logging.log("error while rendering default image: " + err);
  105. }
  106. sendimage(http_status, img_status, def_img);
  107. });
  108. });
  109. }
  110. }
  111. function sendimage(http_status, img_status, image) {
  112. logging.log("status: " + http_status);
  113. res.writeHead(http_status, {
  114. "Content-Type": "image/png",
  115. "Cache-Control": "max-age=" + config.browser_cache_time + ", public",
  116. "Response-Time": new Date() - start,
  117. "X-Storage-Type": human_status[img_status],
  118. "Access-Control-Allow-Origin": "*",
  119. "Etag": '"' + etag + '"'
  120. });
  121. res.end(http_status == 304 ? null : image);
  122. }
  123. };