server.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. #!/usr/bin/env node
  2. var querystring = require("querystring");
  3. var response = require("./response");
  4. var toobusy = require("toobusy-js");
  5. var logging = require("./logging");
  6. var config = require("./config");
  7. var http = require("http");
  8. var mime = require("mime");
  9. var path = require("path");
  10. var url = require("url");
  11. var fs = require("fs");
  12. var server = null;
  13. var routes = {
  14. index: require("./routes/index"),
  15. avatars: require("./routes/avatars"),
  16. skins: require("./routes/skins"),
  17. renders: require("./routes/renders"),
  18. capes: require("./routes/capes")
  19. };
  20. // serves assets from lib/public
  21. function asset_request(req, callback) {
  22. var filename = path.join(__dirname, "public", req.url.path_list.join("/"));
  23. fs.exists(filename, function(exists) {
  24. if (exists) {
  25. fs.readFile(filename, function(err, data) {
  26. callback({
  27. body: data,
  28. type: mime.lookup(filename),
  29. err: err
  30. });
  31. });
  32. } else {
  33. callback({});
  34. }
  35. });
  36. }
  37. // generates a 12 character random string
  38. function request_id() {
  39. return Math.random().toString(36).substring(2, 14);
  40. }
  41. // splits a URL path into an Array
  42. // the path is resolved and decoded
  43. function path_list(pathname) {
  44. // remove double and trailing slashes
  45. pathname = pathname.replace(/\/\/+/g, "/").replace(/(.)\/$/, "$1");
  46. var list = pathname.split("/");
  47. list.shift();
  48. for (var i = 0; i < list.length; i++) {
  49. // URL decode
  50. list[i] = querystring.unescape(list[i]);
  51. }
  52. return list;
  53. }
  54. function requestHandler(req, res) {
  55. req.url = url.parse(req.url, true);
  56. req.url.query = req.url.query || {};
  57. req.url.path_list = path_list(req.url.pathname);
  58. req.id = request_id();
  59. req.start = Date.now();
  60. var local_path = req.url.path_list[0];
  61. logging.log(req.id, req.method, req.url.href);
  62. if (toobusy()) {
  63. res.writeHead(503, {
  64. "Content-Type": "text/plain"
  65. });
  66. res.end("Server is over capaacity :/");
  67. return;
  68. }
  69. if (req.method === "GET" || req.method === "HEAD") {
  70. try {
  71. switch (local_path) {
  72. case "":
  73. routes.index(req, function(result) {
  74. response(req, res, result);
  75. });
  76. break;
  77. case "avatars":
  78. routes.avatars(req, function(result) {
  79. response(req, res, result);
  80. });
  81. break;
  82. case "skins":
  83. routes.skins(req, function(result) {
  84. response(req, res, result);
  85. });
  86. break;
  87. case "renders":
  88. routes.renders(req, function(result) {
  89. response(req, res, result);
  90. });
  91. break;
  92. case "capes":
  93. routes.capes(req, function(result) {
  94. response(req, res, result);
  95. });
  96. break;
  97. default:
  98. asset_request(req, function(result) {
  99. response(req, res, result);
  100. });
  101. }
  102. } catch(e) {
  103. var error = JSON.stringify(req.headers) + "\n" + e.stack;
  104. logging.error(req.id + "Error:", error);
  105. res.writeHead(500, {
  106. "Content-Type": "text/plain"
  107. });
  108. res.end(config.debug_enabled ? error : "Internal Server Error");
  109. }
  110. } else {
  111. res.writeHead(405, {
  112. "Content-Type": "text/plain"
  113. });
  114. res.end("Method Not Allowed");
  115. }
  116. }
  117. var exp = {};
  118. exp.boot = function(callback) {
  119. var port = process.env.PORT || 3000;
  120. var bind_ip = process.env.BIND || "0.0.0.0";
  121. logging.log("Server running on http://" + bind_ip + ":" + port + "/");
  122. server = http.createServer(requestHandler).listen(port, bind_ip, function() {
  123. if (callback) {
  124. callback();
  125. }
  126. });
  127. };
  128. exp.close = function(callback) {
  129. server.close(function() {
  130. callback();
  131. });
  132. };
  133. module.exports = exp;
  134. if (require.main === module) {
  135. logging.error("Please use 'npm start' or 'www.js'");
  136. process.exit(1);
  137. }