ftpd.js
Version:
A FTP Server made in node.js
253 lines (232 loc) • 7.12 kB
JavaScript
//Imports
var util = require( "util" ),
path = require( "path" ),
EventEmitter = require( "events" ).EventEmitter,
Interface = require( "./interface.js" );
/**
*
* @access public
* @constructor
* @since 0.6.0
* @type {Server}
*/
function Server( ftpdjs, options ) {
this.ftpdjs = ftpdjs;
this.id = options.id;
this.options = options;
//Check if the interface path have been defined or not
if ( undefined === this.getOptions().interfacePath ) {
//Add the default interface path
this.getOptions().interfacePath = [ "./interfaces" ];
}
this.interfaces = [];
this.closeIndex = 0;
this.setupCounter = 0;
EventEmitter.call( this );
}
util.inherits( Server, EventEmitter );
/**
*
* This callback will get invoked when the server have finished setting up all of the interfaces it wished to utilize
*
* @callback Server~finishSetup
* @since 0.6.0
*/
/**
*
* This function will be invoked by the application when the server instance have been successfully stored
* in the application's main class. Use this to start and listen the interfaces needed.
*
* Setup Process
* - Setup User Manager
* - Setup All Interfaces
*
* @access public
* @param {Server~finishSetup} callback the callback to invoke when finished
* @since 0.6.0
*/
Server.prototype.setup = function ( callback ) {
//Get the array of available interface configurations
var interfaceConfigurations = this.getOptions().interfaces || [],
that = this;
this.getFtpdjs().log( this.getBaseMessage() + ": Setting up" );
function setupCallback( theInterface ) {
that.getInterfaces().push( theInterface );
that.setupCounter++;
if ( that.setupCounter === that.getOptions().interfaces.length ) {
that.emit( "state", "setup" );
that.getFtpdjs().log( that.getBaseMessage() + ": Finished setting up" );
if ( undefined !== callback ) {
try {
callback();
} catch ( e ) {
}
}
}
}
//Loop through all of the interface configurations
for ( var i = 0; i < interfaceConfigurations.length; i++ ) {
var interfaceOptions = interfaceConfigurations[ i ],
type = interfaceOptions.type;
interfaceOptions.id = that.getID() + i;
if ( undefined === interfaceOptions.type ) {
var theInterface = new Interface( this, interfaceOptions );
theInterface.setup( setupCallback );
} else {
this.getInterfaceFile( type, function ( path ) {
if ( undefined !== path ) {
var interfaceModule = require( path ),
theInterface = new interfaceModule( this, interfaceOptions );
theInterface.setup( setupCallback );
}
} );
}
}
};
/**
*
* @callback Server~finishClose
* @since 0.6.0
*/
/**
*
* This method is used to close all of the interfaces the server is currently utilizing
*
* @access public
* @param {Supervisor~finishClose} callback the callback to invoke upon completed closure of the interfaces
* @since 0.6.0
*/
Server.prototype.close = function ( callback ) {
//Check if we've been through all of the interfaces or if there even is interface in use
if ( this.getInterfaces().length === (this.closeIndex) || 0 == this.getInterfaces().length ) {
//Invoke the callback as there's nothing more to close
this.interfaces = [];
this.getFtpdjs().log( this.getBaseMessage() + ": Closed" );
try {
callback();
} catch ( e ) {
}
return;
}
//Get the next interface and increment the interface close counter
var serverInterface = this.getInterfaces()[ this.closeIndex++ ],
//Setup a this reference as we can't use this within a callback
that = this;
try {
//Close the interface
serverInterface.close( function () {
//Continue to the next interface
that.close( callback );
} )
} catch ( exception ) {
//@TODO Error Handling
}
};
/**
*
* This callback will be invoked when the server finished looking for the wanted interface class
*
* @callback Server~interfaceFile
* @param {string|undefined} interfacePath this will be the full path if the class was found otherwise it'll be
* undefined
* @since 0.6.0
*/
/**
*
* This function is used to search for the wanted interface class in the interfaces paths provided by the server's
* options
*
* @param {string} name the name of the interface
* @param {Server~interfaceFile} callback the callback to invoke when finished looking for the class
* @param {int} index the current path index. Use this if you want to ignore the paths defined before index
*/
Server.prototype.getInterfaceFile = function ( name, callback, index ) {
index = index || 0;
try {
var interfacePath = path.join( this.getOptions().interfacePath[ index ], type + ".js" ),
that = this;
fs.exists( interfacePath, function ( exists ) {
if ( !exists ) {
that.getInterfaceFile( type, callback, index + 1 );
} else {
callback( interfacePath );
}
} )
} catch ( e ) {
callback( undefined );
}
};
/**
*
* @access public
* @returns {ftpdjs} the ftpdjs instance using the server
* @since 0.6.0
*/
Server.prototype.getFtpdjs = function () {
return this.ftpdjs;
};
/**
*
* This function is used to get the id of the server
*
* @access public
* @returns {string} the id of the server
* @since 0.6.0
*/
Server.prototype.getID = function () {
return this.id;
};
/**
*
* This function is used to get the server's options
*
* @access public
* @returns {Object} the server's options
* @since 0.6.0
*/
Server.prototype.getOptions = function () {
return this.options;
};
/**
*
* This function is used to get the array of interfaces the server is utilizing
*
* @access public
* @returns {Array} the initialized interfaces
* @since 0.6.0
*/
Server.prototype.getInterfaces = function () {
return this.interfaces;
};
/**
*
* This function is used to tell wether or not all of the interfaces the server have to utilize have been setup
*
* @access public
* @returns {boolean} wether or not all of the interfaces have been setup
* @since 0.6.0
*/
Server.prototype.isSetup = function () {
return this.getInterfaces().length === this.setupCounter;
};
/**
*
* This function is used to get the base logging message for the server
*
* @access public
* @returns {string} the base log message
* @since 0.6.o
*/
Server.prototype.getBaseMessage = function () {
return "[Server " + this.getID() + "]";
};
Server.prototype.getUserManager = function(){
return this.userManager;
}
/**
*
* @access public
* @type {Server}
* @since 0.6.0
*/
module.exports = Server;