server.js 3.4 KB

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