Source: NodeApiServer.js

"use strict";

// jshint ignore: start

// Import external names locally
var Shared = require('./Shared'),
	NodeApiCollection = require('./NodeApiCollection'),
	express = require('express'),
	app = express(),
	Db,
	DbInit,
	NodeApiServer,
	Overload;

NodeApiServer = function () {
	this.init.apply(this, arguments);
};

/**
 * The init method that can be overridden or extended.
 * @param {Db} db The ForerunnerDB database instance.
 */
NodeApiServer.prototype.init = function (db) {
	var self = this;
	self._db = db;
	self._access = {};
};

Shared.addModule('NodeApiServer', NodeApiServer);
Shared.mixin(NodeApiServer.prototype, 'Mixin.Common');
Shared.mixin(NodeApiServer.prototype, 'Mixin.ChainReactor');

Db = Shared.modules.Db;
DbInit = Db.prototype.init;
Overload = Shared.overload;

/**
 * Starts the rest server listening for requests against the ip and
 * port number specified.
 * @param {String} host The IP address to listen on, set to 0.0.0.0 to
 * listen on all interfaces.
 * @param {Number} port The port to listen on.
 * @param {Function=} callback The method to call when the server has
 * started (or failed to start).
 * @returns {NodeApiServer}
 */
NodeApiServer.prototype.listen = function (host, port, callback) {
	var self = this;

	self._server = app.listen(port, host, function () {
		console.log('Listening at http://%s:%s', host, port);
		callback(false, self._server);
	});

	return this;
};

NodeApiServer.prototype.access = new Overload({
	'': function () {
		return this.$main.call(this);
	},

	'string': function (modelName) {
		return this.$main.call(this, modelName);
	},

	'string, function': function (modelName, method) {
		return this.$main.call(this, modelName, '*', method);
	},

	'string, string': function (modelName, methodName) {
		return this.$main.call(this, modelName, methodName);
	},

	'string, string, function': function (modelName, methodName, method) {
		return this.$main.call(this, modelName, methodName, method);
	},

	/**
	 * Defines an access rule for a model and method combination. When
	 * access is requested via a REST call, the function provided will be
	 * executed and the callback from that method will determine if the
	 * access will be allowed or denied. Multiple access functions can
	 * be provided for a single model and method allowing authentication
	 * checks to be stacked.
	 * @name access
	 * @param {String} modelName The model name (collection) to apply the
	 * access function to.
	 * @param {String} methodName The name of the method to apply the access
	 * function to e.g. "insert".
	 * @param {Function} method The function to call when an access attempt
	 * is made against the collection. A callback method is passed to this
	 * function which should be called after the function has finished
	 * processing.
	 * @returns {*}
	 */
	'$main': function (modelName, methodName, method) {
		if (modelName !== undefined) {
			if (methodName !== undefined) {
				if (method !== undefined) {
					this._access[modelName] = this._access[modelName] || {};
					this._access[modelName][methodName] = this._access[modelName][methodName] || [];
					this._access[modelName][methodName].push(method);

					return this;
				}

				if (this._access[modelName] && this._access[modelName][methodName]) {
					return this._access[modelName][methodName];
				}

				return [];
			}

			if (this._access[modelName]) {
				return this._access[modelName];
			}

			return {};
		}

		return this._access;
	}
});

// Override the DB init to instantiate the plugin
Db.prototype.init = function () {
	DbInit.apply(this, arguments);
	this.api = new NodeApiServer(this);
};

Shared.finishModule('NodeApiServer');

module.exports = NodeApiServer;