11ab9c91dde1f7bcd4011847aca07bd66783cf3f
[yaffs-website] / node_modules / phridge / lib / phantom / start.js
1 // Not using strict mode here because strict mode has an impact on evaled source code
2
3 /* eslint-disable no-unused-vars, camelcase */
4 // Yep, they are unused intentionally. They are just available for convenience reasons.
5 var webpage = require("webpage");
6 var system = require("system");
7 var fs = require("fs");
8 var webserver = require("webserver");
9 var child_process = require("child_process");
10 var configPath = system.args[1];
11 var config = JSON.parse(fs.read(configPath));
12 /*eslint-enable no-unused-vars, camelcase */
13 var pages = {};
14 var context = {};
15 var commandHandlers = {};
16
17 /**
18  * Reads a line from stdin and calls the requested command handler. Calls itself after setTimeout 0.
19  */
20 function loop() {
21     // stdin.readLine() is sync and halts until a whole line is read
22     var line = system.stdin.readLine();
23     var message = JSON.parse(line);
24     var handler = commandHandlers[message.action];
25
26     if (!handler) {
27         throw new Error("Unknown action '" + message.action + "'");
28     }
29
30     handler(message);
31
32     setTimeout(loop, 0);
33 }
34
35 /**
36  * Returns a function that should be called to return the result for this message.
37  *
38  * @param {Object} message
39  * @returns {resolve}
40  */
41 function createResolver(message) {
42     /**
43      * @param {Object} data
44      */
45     function resolve(data) {
46         write({
47             status: "success",
48             id: message.done ? null : message.id,
49             data: data
50         });
51         message.done = true;
52     }
53
54     return resolve;
55 }
56
57 /**
58  * Returns a function that should be called to indicate that this message yielded to an error.
59  *
60  * @param {Object} message
61  * @returns {reject}
62  */
63 function createRejecter(message) {
64     /**
65      * @param {Object} data
66      */
67     function reject(data) {
68         var stack;
69
70         try {
71             throw new Error(data ? data.message || "Error" : "Error");
72         } catch (err) {
73             stack = err.stack;
74
75             stack += "\n" +
76                 "    -----------------------------------------------------------------------\n" +
77                 message.from;
78
79             data = {
80                 message: err.message,
81                 stack: stack
82             };
83         }
84
85         write({
86             status: "fail",
87             id: message.done ? null : message.id,
88             data: data
89         });
90         message.done = true;
91     }
92
93     return reject;
94 }
95
96 /**
97  * Runs message.data.src in the given context.
98  *
99  * @param {Object} message
100  * @param {Object} context
101  */
102 function run(message, context) {
103     var resolve = createResolver(message);
104     var reject = createRejecter(message);
105
106     try {
107         evalSrc(message.data.src, context, resolve, reject);
108     } catch (err) {
109         reject(err);
110     }
111 }
112
113 /**
114  * Helper function for run() to avoid scope pollution. `context`, `resolve` and `reject` are needed according
115  * to the serializeFn-module.
116  *
117  * @param {string} src
118  * @param {object} context
119  * @param {Function} resolve
120  * @param {Function} reject
121  */
122 function evalSrc(src, context, resolve, reject) {
123     eval(src); // eslint-disable-line
124 }
125
126 /**
127  * Helper function that stringifies the given object and writes it to system.stdout
128  *
129  * @param {Object} message
130  */
131 function write(message) {
132     system.stdout.writeLine("message to node: " + JSON.stringify(message));
133 }
134
135 /**
136  * Collection of request-able commands (as defined in the action-property of the message).
137  *
138  * @type {Object}
139  */
140 commandHandlers = {
141
142     /**
143      * The ping command is a neat trick so PhantomJS isn't stuck in the stdin.readLine()-loop
144      * while waiting for an asynchronous event. A ping-command is sent by node as long as it
145      * waits for PhantomJS to respond. We're responding with a pong to tell node that we're waiting
146      * for the next ping.
147      */
148     ping: function () {
149         write({
150             status: "pong"
151         });
152     },
153
154     /**
155      * Runs message.data.src in the default context.
156      *
157      * @param {Object} message
158      */
159     run: function (message) {
160         run(message, context);
161     },
162
163     /**
164      * Runs message.data.src in the requested page context. If the page context doesn't exist, a new webpage
165      * is created implicitly.
166      *
167      * @param {Object} message
168      */
169     "run-on-page": function (message) {
170         var pageId = message.data.pageId;
171         var page = pages[pageId];
172
173         if (!page) {
174             pages[pageId] = page = webpage.create();
175         }
176
177         run(message, page);
178     }
179 };
180
181 // remove the config as it is not needed anymore
182 fs.remove(configPath);
183
184 // send hi to node so node knows that we're ready
185 system.stdout.writeLine("message to node: hi");
186
187 loop();