mirror of
https://github.com/sstent/node.git
synced 2026-01-27 07:33:13 +00:00
167 lines
4.6 KiB
JavaScript
167 lines
4.6 KiB
JavaScript
var fs = require('fs')
|
|
, path = require('path')
|
|
, http = require('http')
|
|
, racer = require('racer')
|
|
, tracks = require('tracks')
|
|
, up = require('up')
|
|
, View = require('./View.server')
|
|
, autoRefresh = require('./refresh.server').autoRefresh
|
|
, util = racer.util
|
|
, merge = util.merge
|
|
, isProduction = util.isProduction
|
|
, proto;
|
|
|
|
module.exports = derbyServer;
|
|
|
|
function derbyServer(derby) {
|
|
merge(derby, proto);
|
|
|
|
Object.defineProperty(derby, 'version', {
|
|
get: function() {
|
|
return require('../package.json').version;
|
|
}
|
|
});
|
|
}
|
|
derbyServer.decorate = 'derby';
|
|
derbyServer.useWith = {server: true, browser: false};
|
|
|
|
|
|
proto = {
|
|
// TODO: Remove in lieu of get / set methods
|
|
options: {}
|
|
|
|
, run: function(file, port, options) {
|
|
var master, onMessage, server, upService;
|
|
|
|
// Resolve relative filenames
|
|
file = path.resolve(file);
|
|
if (port == null) port = isProduction ? 80 : 3000;
|
|
if (options == null) options = {numWorkers: 1};
|
|
|
|
try {
|
|
server = require(file);
|
|
} catch (e) {
|
|
console.error('Error requiring server module from `%s`', file);
|
|
throw e;
|
|
}
|
|
if (!(server instanceof http.Server)) {
|
|
throw new Error('`' + file + '` does not export a valid `http.Server`');
|
|
}
|
|
if (!isProduction) {
|
|
// TODO: This extends the internal API of Up. It would be better
|
|
// if Up supported workers being able to force a global reload
|
|
onMessage = up.Worker.prototype.onMessage;
|
|
up.Worker.prototype.onMessage = function(message) {
|
|
if (message.type === 'reload') {
|
|
return upService.reload();
|
|
}
|
|
onMessage.call(this, message);
|
|
};
|
|
}
|
|
master = http.createServer().listen(port);
|
|
upService = up(master, file, options);
|
|
process.on('SIGUSR2', function() {
|
|
console.log('SIGUSR2 signal detected - reloading');
|
|
upService.reload();
|
|
});
|
|
console.log('Starting cluster with %d workers in %s mode',
|
|
options.numWorkers, process.env.NODE_ENV);
|
|
console.log('`kill -s SIGUSR2 %s` to force cluster reload', process.pid);
|
|
console.log('Go to: http://localhost:%d/', port);
|
|
}
|
|
|
|
, createApp: function(appModule) {
|
|
var appExports = appModule.exports
|
|
, view = new View(this._libraries)
|
|
, options = this.options
|
|
, session, store;
|
|
|
|
view._derbyOptions = options;
|
|
view._appFilename = appModule.filename;
|
|
function setStore(_store) {
|
|
autoRefresh(_store, options, view);
|
|
if (session != null) session._setStore(_store);
|
|
return store = _store;
|
|
}
|
|
|
|
// Expose methods on the application module
|
|
|
|
function Page(model, res) {
|
|
this._model = model;
|
|
this._res = res;
|
|
}
|
|
Page.prototype.render = function(ns, ctx, status) {
|
|
view.render(this._res, this._model, ns, ctx, status);
|
|
};
|
|
|
|
function createPage(req, res) {
|
|
var model = req.model || store.createModel();
|
|
return new Page(model, res);
|
|
}
|
|
function onRoute(callback, page, params, next, isTransitional) {
|
|
if (isTransitional) {
|
|
callback(page._model, params, next);
|
|
} else {
|
|
callback(page, page._model, params, next);
|
|
}
|
|
}
|
|
tracks.setup(appExports, createPage, onRoute);
|
|
|
|
appExports._setStore = setStore;
|
|
appExports.view = view;
|
|
appExports.ready = function() {};
|
|
appExports.createStore = function(options) {
|
|
return setStore(racer.createStore(options));
|
|
};
|
|
appExports.session = function() {
|
|
return session = racer.session(store);
|
|
};
|
|
appExports.render = function(res, model, ns, ctx, status) {
|
|
return view.render(res, model, ns, ctx, status);
|
|
};
|
|
|
|
// Render immediately upon creating the app so that files
|
|
// will be cached for the first render
|
|
process.nextTick(function() {
|
|
view.render();
|
|
});
|
|
return appExports;
|
|
}
|
|
|
|
, createStatic: function(root) {
|
|
return new Static(root, this._libraries);
|
|
}
|
|
|
|
, createStore: function() {
|
|
var len = arguments.length
|
|
, last = arguments[len - 1]
|
|
, options, app, store;
|
|
// Last argument may be a createStore options object
|
|
if (!last.view) {
|
|
options = last;
|
|
len--;
|
|
}
|
|
store = racer.createStore(options);
|
|
for (var i = len; i--;) {
|
|
app = arguments[i];
|
|
app._setStore(store);
|
|
}
|
|
return store;
|
|
}
|
|
};
|
|
|
|
function Static(root, libraries) {
|
|
this.root = root;
|
|
this.libraries = libraries;
|
|
this.views = {};
|
|
}
|
|
Static.prototype.render = function(name, res, model, ns, ctx, status) {
|
|
var view = this.views[name];
|
|
if (!view) {
|
|
view = this.views[name] = new View(this.libraries);
|
|
view._root = this.root;
|
|
view._clientName = name;
|
|
}
|
|
view.render(res, model, ns, ctx, status, true);
|
|
};
|