removed signal listeners
[xtuple] / node-datasource / xt / xt.js
1 /*jshint node:true, bitwise:true, indent:2, curly:true, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
2 regexp:true, undef:true, strict:true, trailing:true, white:true */
3 /*global X:true, XT:true */
4
5 /**
6   The X Node.js framework is comprised of 3 major components. The foundation,
7   the database and the server. The foundation can be used on its own. database
8   and server can be used with or without the other but both require the foundation.
9
10   It is important to note the scoping of the namespace. Unlike most modules that
11   do not expose their scope, X modules and components share the namespace without
12   explicitly exporting it. The global variable X is common to any modules that are
13   required after its initial instantiation
14
15   It is possible for submodules of the framework to reserve initialization routines
16   until after the framework itself has been fully loaded and initialized. There is
17   an exposed routine in X called `run` that expects a single paramter that is a callback
18   that will be executed in the order it was received. Currently there is no implementation
19   that allows for a module to hook another unless the order of loading is known and
20   the first module emits an event that the second module knows to listen for and receive.
21
22   There are known limitations in its current implementation in the object hierarchy and
23   some of the convenience mechanisms built-in.
24 */
25
26 //.........................................
27 // Include the foundation that instantiates the
28 // X global namespace
29 require('./foundation');
30 XT = { };
31
32 (function () {
33   "use strict";
34
35   var _ = X._, _path = X.path, sighandler;
36
37   sighandler = function (signal) {
38
39     // mostly for logging, make sure anything that wants to know can
40     // easily find why we're shutting down
41     X.SHUTDOWN_SIGNAL = signal;
42     X.io.console(X.StringBuffer.create({color: "blue", prefix: null}),
43       "\n================================================" +
44       "\n%@ CAUGHT - cleaning up before shutting down".f(signal.toUpperCase()) +
45       "\n================================================"
46     );
47     // this is a workaround. We want to be able to dictate the exit code. As a convention
48     // we'll say that SIGKILL is the error exit code of 1 and all the rest are the normal
49     // error code of 0
50     X.cleanup(signal === 'SIGKILL');
51   };
52
53   // the first method to run once the framework has been told it is
54   // ready
55   X.run(function () {
56
57     var i, sub;
58
59     // special case where the desired output requires calling console directly
60     X.io.console(X.StringBuffer.create({ color: 'blue', prefix: null }),
61       "\n================================================" +
62       "\nXTUPLE NODE.JS SERVER" +
63       "\n================================================\n"
64     );
65
66     require("./database");
67
68     X.pid = process.pid;
69
70     // must explicitly be set to false for it to know you do not want
71     // a pidfile!
72     if (X.pidFile !== false) {
73       if (!X.pidFilePath) {
74         X.pidFilePath = "%@/pid".f(X.basePath);
75       } else if (X.pidFilePath.indexOf(X.basePath) === -1) {
76         X.pidFilePath = _path.join(X.basePath, X.pidFilePath);
77       }
78       if (!X.pidFileName) {
79         X.pidFileName = "%@.pid".f(X.options.processName ? X.options.processName: "node_xt_process");
80       } else if (X.pidFileName.indexOf(".pid") === -1) {
81         X.pidFileName = X.pidFileName.suf(".pid");
82       }
83
84       // if we're allowed to have multiples of this resource executing
85       // simultaneously we need to make the name unique
86       if (X.options.allowMultipleInstances === true) {
87         i = X.pidFileName.indexOf(".pid");
88         sub = X.pidFileName.substring(0, i);
89         X.pidFileName = "%@_%@.pid".f(sub, X.pid);
90       }
91
92       // keep track of the actual pidfile full path
93       X.pidFile = _path.join(X.pidFilePath, X.pidFileName);
94
95       X.exists(X.pidFile, function (exists) {
96         if (exists && !X.options.allowMultipleInstances) {
97           X.error("Multiple instances are not allowed");
98         } else {
99
100           // write our pidfile...
101           X.exists(_path.join(X.pidFilePath), function (exists) {
102             if (!exists) {
103               X.createDir(X.pidFilePath, X.writePidFile);
104             }
105             else {
106               X.writePidFile();
107             }
108           });
109         }
110       });
111     }
112
113     // give any running process the opportunity to save state
114     // or log as gracefully as possible
115     process.once('exit', _.bind(X.cleanup, X));
116   });
117 }());