index.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. var Q = require("q");
  2. var fs = require("fs");
  3. var ncp = require("ncp").ncp;
  4. var os = require("os");
  5. var path = require("path");
  6. var spawn = require("child_process").spawn;
  7. var wrench = require("wrench");
  8. try {
  9. var platform_cli = require('atomic-cli-mac');
  10. console.log(platform_cli);
  11. }
  12. catch (e) {
  13. console.log(e);
  14. }
  15. var DATA_DIR = platform_cli.EDITOR_DATA_DIR;
  16. exports.DATA_DIR = DATA_DIR;
  17. var ATOMIC_TOOL_BIN = platform_cli.ATOMICTOOL_BIN;
  18. var HTTP_PORT = 4000;
  19. var SOCKET_PORT = HTTP_PORT+1;
  20. exports.PLATFORMS = ["windows", "mac", "android", "ios", "web"];
  21. exports.VERSION = JSON.parse(fs.readFileSync(__dirname + "/package.json")).version;
  22. var exec = function (command, flags, opts) {
  23. opts = opts || {};
  24. if (opts.verbose !== false) {
  25. console.log([command].concat(flags).join(" "));
  26. }
  27. // Run everything through cmd.exe on Windows to be able to find .bat files
  28. if (process.platform == "win32" && opts.windowsCmd !== false) {
  29. flags.unshift("/c", command);
  30. command = "cmd";
  31. }
  32. var deferred = Q.defer();
  33. var child = spawn(command, flags, {stdio: (opts.output === false) ? "ignore" : "inherit"});
  34. child.on("close", function (code) {
  35. if (code && opts.check !== false) {
  36. deferred.reject();
  37. }
  38. deferred.resolve(code);
  39. });
  40. child.on("error", function (error) {
  41. deferred.reject(error);
  42. });
  43. return deferred.promise;
  44. };
  45. exports.exec = exec;
  46. var atomictool = function (flags, opts) {
  47. opts = opts || {};
  48. opts.windowsCmd = false;
  49. flags.unshift(DATA_DIR);
  50. flags.unshift("--cli-data-path");
  51. return exec(ATOMIC_TOOL_BIN, flags, opts);
  52. };
  53. exports.atomictool = atomictool
  54. exports.newProject = function (output) {
  55. return atomictool(["new", output], {output:true});
  56. };
  57. exports.build = function (platform) {
  58. return atomictool(["build", platform], {output:true});
  59. };
  60. exports.addPlatform = function (platform) {
  61. return atomictool(["platform-add", platform], {output:true});
  62. };
  63. exports.run = function (platform, opts) {
  64. opts = opts || {};
  65. var debug = opts.debug;
  66. if (platform == null) {
  67. // platform = get(config, "default_platform", "flash");
  68. }
  69. //checkPlatforms([platform]);
  70. var run = function () {
  71. switch (platform) {
  72. case "web":
  73. var url = "http://localhost:" + HTTP_PORT + "/AtomicPlayer.html";
  74. console.log("Launching: " + url);
  75. var open = require("open");
  76. open(url);
  77. break;
  78. case "mac":
  79. var open = require("open");
  80. open("Build/Mac-Build/AtomicPlayer.app");
  81. break;
  82. }
  83. };
  84. return opts.noBuild ? run() : exports.build([platform], opts).then(function () {
  85. console.log();
  86. return run();
  87. });
  88. };
  89. // Web Server (from flambe: https://raw.githubusercontent.com/aduros/flambe/master/command/index.js)
  90. var Server = function () {
  91. };
  92. exports.Server = Server;
  93. Server.prototype.start = function () {
  94. var self = this;
  95. var connect = require("connect");
  96. var url = require("url");
  97. var websocket = require("websocket");
  98. // Fire up a Haxe compiler server, ignoring all output. It's fine if this command fails, the
  99. // build will fallback to not using a compiler server
  100. // spawn("haxe", ["--wait", HAXE_COMPILER_PORT], {stdio: "ignore"});
  101. // Start a static HTTP server
  102. var host = "0.0.0.0";
  103. var staticServer = connect()
  104. .use(function (req, res, next) {
  105. var parsed = url.parse(req.url, true);
  106. if (parsed.pathname == "/_api") {
  107. // Handle API requests
  108. req.setEncoding("utf8");
  109. req.on("data", function (chunk) {
  110. self._onAPIMessage(chunk)
  111. .then(function (result) {
  112. res.end(JSON.stringify({result: result}));
  113. })
  114. .catch(function (error) {
  115. res.end(JSON.stringify({error: error}));
  116. });
  117. });
  118. } else {
  119. if (parsed.query.v) {
  120. // Forever-cache assets
  121. var expires = new Date(Date.now() + 1000*60*60*24*365*25);
  122. res.setHeader("Expires", expires.toUTCString());
  123. res.setHeader("Cache-Control", "max-age=315360000");
  124. }
  125. next();
  126. }
  127. })
  128. .use(connect.logger("tiny"))
  129. .use(connect.compress())
  130. .use(connect.static("Build/Web-Build"))
  131. .listen(HTTP_PORT, host);
  132. console.log("Serving on http://localhost:%s", HTTP_PORT);
  133. this._wsServer = new websocket.server({
  134. httpServer: staticServer,
  135. autoAcceptConnections: true,
  136. });
  137. this._wsServer.on("connect", function (connection) {
  138. connection.on("message", function (message) {
  139. if (message.type == "utf8") {
  140. self._onMessage(message.utf8Data);
  141. }
  142. });
  143. });
  144. var net = require("net");
  145. this._connections = [];
  146. this._socketServer = net.createServer(function (connection) {
  147. self._connections.push(connection);
  148. connection.on("end", function () {
  149. self._connections.splice(self._connections.indexOf(connection, 1));
  150. });
  151. connection.on("data", function (data) {
  152. data = data.toString();
  153. self._onMessage(data);
  154. });
  155. });
  156. this._socketServer.listen(SOCKET_PORT, host);
  157. var watch = require("watch");
  158. var crypto = require("crypto");
  159. watch.createMonitor("Resources", {interval: 200}, function (monitor) {
  160. monitor.on("changed", function (file) {
  161. console.log("Asset changed: " + file);
  162. var output = "build/web/"+file;
  163. if (fs.existsSync(output)) {
  164. var contents = fs.readFileSync(file);
  165. fs.writeFileSync(output, contents);
  166. self.broadcast("file_changed", {
  167. name: path.relative("Resources", file),
  168. md5: crypto.createHash("md5").update(contents).digest("hex"),
  169. });
  170. }
  171. });
  172. });
  173. };
  174. /** Broadcast an event to all clients. */
  175. Server.prototype.broadcast = function (type, params) {
  176. var event = {type: type};
  177. if (params) {
  178. for (var k in params) {
  179. event[k] = params[k];
  180. }
  181. }
  182. var message = JSON.stringify(event);
  183. this._wsServer.broadcast(message);
  184. this._connections.forEach(function (connection) {
  185. connection.write(message);
  186. });
  187. };
  188. /** Handle messages from connected game clients. */
  189. Server.prototype._onMessage = function (message) {
  190. try {
  191. var event = JSON.parse(message);
  192. // switch (event.type) {
  193. // case "restart":
  194. // this.broadcast("restart");
  195. // }
  196. } catch (error) {
  197. console.warn("Received badly formed message", error);
  198. }
  199. };
  200. /** Handle web API messages. */
  201. Server.prototype._onAPIMessage = function (message) {
  202. try {
  203. message = JSON.parse(message);
  204. } catch (error) {
  205. return Q.reject("Badly formed JSON");
  206. }
  207. switch (message.method) {
  208. case "restart":
  209. this.broadcast("restart");
  210. return Q.resolve({
  211. htmlClients: this._wsServer.connections.length,
  212. flashClients: this._connections.length,
  213. });
  214. default:
  215. return Q.reject("Unknown method: " + message.method);
  216. }
  217. };