helpers.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. var networking = require('./networking');
  2. var logging = require('./logging');
  3. var config = require('./config');
  4. var cache = require('./cache');
  5. var skins = require('./skins');
  6. var fs = require('fs');
  7. // 0098cb60-fa8e-427c-b299-793cbd302c9a
  8. var valid_uuid = /^([0-9a-f-]{32,36}|[a-zA-Z0-9_]{1,16})$/; // uuid|username
  9. var hash_pattern = /[0-9a-f]+$/;
  10. function get_hash(url) {
  11. return hash_pattern.exec(url)[0].toLowerCase();
  12. }
  13. // requests skin for +uuid+ and extracts face/helm if image hash in +details+ changed
  14. // callback contains error, image hash
  15. function store_images(uuid, details, callback) {
  16. // get skin_url for +uuid+
  17. networking.get_skin_url(uuid, function(err, skin_url) {
  18. if (err) {
  19. callback(err, null);
  20. } else {
  21. if (skin_url) {
  22. logging.log(uuid + " " + skin_url);
  23. // set file paths
  24. var hash = get_hash(skin_url);
  25. if (details && details.hash == hash) {
  26. // hash hasn't changed
  27. logging.log(uuid + " hash has not changed");
  28. cache.update_timestamp(uuid, hash);
  29. callback(null, hash);
  30. } else {
  31. // hash has changed
  32. logging.log(uuid + " new hash: " + hash);
  33. var facepath = __dirname + '/../' + config.faces_dir + hash + ".png";
  34. var helmpath = __dirname + '/../' + config.helms_dir + hash + ".png";
  35. if (fs.existsSync(facepath)) {
  36. logging.log(uuid + " Avatar already exists, not downloading");
  37. callback(null, hash);
  38. } else {
  39. // download skin
  40. networking.get_skin(skin_url, function(err, img) {
  41. if (err || !img) {
  42. callback(err, null);
  43. } else {
  44. // extract face / helm
  45. skins.extract_face(img, facepath, function(err) {
  46. if (err) {
  47. callback(err);
  48. } else {
  49. logging.log(uuid + " face extracted");
  50. logging.debug(facepath);
  51. skins.extract_helm(facepath, img, helmpath, function(err) {
  52. logging.log(uuid + " helm extracted");
  53. logging.debug(helmpath);
  54. cache.save_hash(uuid, hash);
  55. callback(err, hash);
  56. });
  57. }
  58. });
  59. }
  60. });
  61. }
  62. }
  63. } else {
  64. // profile found, but has no skin
  65. cache.save_hash(uuid, null);
  66. callback(null, null);
  67. }
  68. }
  69. });
  70. }
  71. var exp = {};
  72. // returns true if the +uuid+ is a valid uuid or username
  73. // the uuid may be not exist, however
  74. exp.uuid_valid = function(uuid) {
  75. return valid_uuid.test(uuid);
  76. };
  77. // decides whether to get an image from disk or to download it
  78. // callback contains error, status, hash
  79. // the status gives information about how the image was received
  80. // -1: "error"
  81. // 0: "none" - cached as null
  82. // 1: "cached" - found on disk
  83. // 2: "downloaded" - profile downloaded, skin downloaded from mojang servers
  84. // 3: "checked" - profile re-downloaded (was too old), but it has either not changed or has no skin
  85. exp.get_image_hash = function(uuid, callback) {
  86. cache.get_details(uuid, function(err, details) {
  87. if (err) {
  88. callback(err, -1, null);
  89. } else {
  90. if (details && details.time + config.local_cache_time * 1000 >= new Date().getTime()) {
  91. // uuid known + recently updated
  92. logging.log(uuid + " uuid cached & recently updated");
  93. callback(null, (details.hash ? 1 : 0), details.hash);
  94. } else {
  95. if (details) {
  96. logging.log(uuid + " uuid cached, but too old");
  97. } else {
  98. logging.log(uuid + " uuid not cached");
  99. }
  100. store_images(uuid, details, function(err, hash) {
  101. if (err) {
  102. callback(err, -1, details && details.hash);
  103. } else {
  104. logging.log(uuid + " hash: " + hash);
  105. var oldhash = details && details.hash;
  106. var status = hash !== oldhash ? 2 : 3;
  107. callback(null, status, hash);
  108. }
  109. });
  110. }
  111. }
  112. });
  113. };
  114. // handles requests for +uuid+ images with +size+
  115. // callback contains error, status, image buffer, hash
  116. // image is the user's face+helm when helm is true, or the face otherwise
  117. // for status, see get_image_hash
  118. exp.get_avatar = function(uuid, helm, size, callback) {
  119. logging.log("\nrequest: " + uuid);
  120. exp.get_image_hash(uuid, function(err, status, hash) {
  121. if (hash) {
  122. var facepath = __dirname + '/../' + config.faces_dir + hash + ".png";
  123. var helmpath = __dirname + '/../' + config.helms_dir + hash + ".png";
  124. var filepath = facepath;
  125. if (helm && fs.existsSync(helmpath)) {
  126. filepath = helmpath;
  127. }
  128. skins.resize_img(filepath, size, function(img_err, result) {
  129. if (img_err) {
  130. callback(img_err, -1, null, hash);
  131. } else {
  132. // we might have a hash although an error occured
  133. // (e.g. Mojang servers not reachable, using outdated hash)
  134. callback(err, (err ? -1 : status), result, hash);
  135. }
  136. });
  137. } else {
  138. // hash is null when uuid has no skin
  139. callback(err, status, null, null);
  140. }
  141. });
  142. };
  143. exp.get_skin = function(uuid, callback) {
  144. logging.log("\nskin request: " + uuid);
  145. exp.get_image_hash(uuid, function(err, status, hash) {
  146. if (hash) {
  147. var skinurl = "http://textures.minecraft.net/texture/" + hash;
  148. networking.get_skin(skinurl, function(err, img) {
  149. if (err) {
  150. logging.log("\nerror while downloading skin");
  151. callback(err, hash, null);
  152. } else {
  153. logging.log("\nreturning skin");
  154. callback(null, hash, img);
  155. }
  156. });
  157. }
  158. });
  159. };
  160. module.exports = exp;