Application classes for Node.js.
npm install https://github.com/Perennials/app-node/tarball/master
Extends App.
Provides a base for building HTTP server applications. The default implementation takes care of reading the whole request and handling errors with node domains, so errors are associated with the proper HTTP request.
To reuse this class one extends the HttpAppRequest class
and provides the constructor to HttpApp
. The latter will install a request
handler and upon receiving a request will instantiate the user's
HttpAppRequest
class. This way all logic associated with the request can be
placed in the proper context.
var HttpApp = require( 'App/HttpApp' );
"use strict";
var HttpApp = require( 'App/HttpApp' );
var HttpAppRequest = require( 'App/HttpAppRequest' );
var RequestRouter = require( 'App/RequestRouter' );
// this will be instantiated by HttpApp whenever we have a new request coming in
class MyAppRequest extends HttpAppRequest {
onError ( err ) {
console.log( 'Damn, error happened with this specific client request', Object.toString( this._request ) );
// finish the response so we can close the server
this._response.writeHead( 500 );
this._response.end();
// call the default handler, which will abort the app
super.onError( err );
}
// this will be called when we have the whole http request
onHttpContent ( content ) {
// we have the full request at this point, headers and content
if ( this._request.headers[ 'content-encoding' ] === 'identity' ) {
console.log( 'The request content is', content.toString( 'utf8' ) );
}
doSomethingWithThe( this._request, function ( good ) {
// normal nodejs handling of the response
this._response.writeHead( good ? 200 : 500, {
'Connection': 'close',
'Content-Type': 'text/plain'
} );
this._response.end( 'bye' );
} );
}
}
// construct a new HttpApp, here we give it a RequestRouter to show its usage,
// but we could replace this with MyAppRequest if have only one request handler
var app = new HttpApp( new class extends RequestRouter {
// just demonstrate how to use the router, it does nothing in this example
route ( app, req ) {
// if we receive a request with header like this we choose one handler
if ( req.headers[ 'my-proc' ] == 'NonExistentProc' ) {
return NonExistentProc;
}
// otherwise we choose other handler
else {
return MyAppRequest;
}
}
} );
app.startListening( 1337, '0.0.0.0' );
Constructor. The appRequestClass
argument is a constructor of a class
derived from HttpAppRequest
. It will be used by onHttpRequest()
to create
a new instance of this class for each incomming request. Alternatively an instance
of RequestRouter
can be passed. Its .route() method will be used
to determine the appropriate HttpAppRequest
class.
new HttpApp(
appRequestClass:Function|RequestRouter
);
Starts listening for HTTP requests.
.startListening(
port:Number,
host:String
);
Closes the HTTP server (http.Server.close). .onClose()
will be called
before the callback.
.close(
callback:function()|undefined
);
Default HTTP request handler called directly from node's http.Server. The
default implementation does the domain handling and calls .onHttpHeaders()
.
Can be overriden for advanced use.
.onHttpRequest( req, res );
May be used with HttpApp
on incomming requests to decide the appropriate
class that will handle the request.
var RequestRouter = require( 'App/RequestRouter' );
This method must be overloaded to decide the class that will handle the request. It returns a reference to the class itself, or in ES5 terms a reference to the function that will construct an instance of this class.
It receives reference to the HttpApp
and nodejs' request object from the
request handler of the HTTP server.
.route(
app:HttpApp,
req:http.IncommingMessage
) : Function;
This class is instantiated by the HttpApp
class when there is incoming
server request.
The object encapsulates node's native types passed to the HTTP request callback, as well as the domain associated with the request. It should be subclassed to override the desired functionality.
var HttpAppRequest = require( 'App/HttpAppRequest' );
- Constructor
- .getApp()
- .getDomain()
- .getRequest()
- .getResponse()
- .onHttpHeaders()
- .onHttpContent()
- .onHttpError()
- .onError()
Constructor. It receives reference to the HttpApp
and nodejs' request and
response objects from the request handler of the HTTP server. This method will
create the node domain and associate it with the request and call
.onHttpHeaders(). Normally this constructor should be called
by the constructor of the derived classes.
new HttpAppRequest(
app:HttpApp,
req:http.IncommingMessage,
res:http.ServerResponse
);
Retrieves the HttpApp associated with this request.
.getApp() : HttpApp;
Retrieves the node Domain associated with this request.
.getDomain() : Domain;
Retrieves the node request associated with this request.
.getRequest() : IncommingMessage;
Retrieves the node response associated with this request.
.getResponse() : ServerResponse;
Called whenever there is HTTP request. The default implementation installs
'data' handler, reads the content and calls .onHttpContent()
. The default
implementation will check the headers and decompress gzip
, deflate
or
snappy
content. Can be overriden in case access to the HTTP headers is
needed before handling the content or for advanced use.
.onHttpHeaders();
Called whenever there is HTTP request and the whole request content is received. Must be overriden.
.onHttpContent(
content:Buffer
);
Called whenever there is 'error' event on the HTTP request.
.onHttpError(
err:Error
);
Called whenever uncaught exception happens in the context of an HTTP request.
The default handler will print the error to stderr and call .close()
on the
.App
objects. Recommended to override.
.onError(
err:Error
);
Base application class for HttpApp
. Not to be used directly.
This class will install .close()
as signal handler for SIGINT
, SIGHUP
,
SIGTERM
, so it will try to close gracefully in all cases by calling .onClose()
,
which is meant to do cleanup.
var App = require( 'App/App' );
Retrieves the process.argv
parsed with Argv.parse()
.
.getArgv() : Object|null;
Performs application specific onClose (as preparation for graceful exit). The default function does nothing but call the callback.
.onClose(
callback:function()|undefined
);
Performs .onClose()
and then calls process.exit( code )
.
.close(
code:Number
);
The Config class provides stack-able object of properties, where the properties in the objects of the upper layers can override the lower layers.
Properties can refer to other properties and have a dynamic (callback) value.
var Config = require( 'App/Config' );
var Config = require( 'App/Config' );
// default language
var ENG = new Config( { hello: 'hello', bye: 'bye' } );
// another language extends the default
var DEU = new Config( { hello: 'hallo', bye: 'auf wiedersehen' }, ENG );
// and yet another one
var langs = new Config( { hello: 'holla' }, DEU );
// static propertiers can be accessed directly
if ( langs.hello == 'holla' ) {
// we have spanish string for hello
}
if ( langs.bye == 'auf wiedersehen' ) {
// we don't have spanish string for bye and we use the german fallback
}
var Config = require( 'App/Config' );
var cfg = new Config( {
shared: {
separator: ', '
},
// we have absolute reference {name.full} and dynamic value {1}
my_name: 'my name is {name.full}; i am {1} years old.',
name: {
first: 'tosho',
last: 'afrikanski',
// this is relative reference from the current node (_) or from the parent node (__)
// _ and __ are equivalent to . and .. when dealing with the file system in the shell
// they can be chained, of course, like __.__.and.so.on
full: '{_.last}{__.shared.separator}{_.first}'
}
} );
if ( cfg.get( 'my_name', 30 ) == 'my name is afrikanski, tosho; i am 30 years old.' ) {
// ...
}
Helps with parsing application command line.
var Argv = require( 'App/Argv' );
var Argv = require( 'App/Argv' );
var argv = Argv.parse( [ '-arg1=value', '-flag', 'arg2', '-arg3=1', '-arg3=2', '-arg3', '--arg4', 'value' ] );
// this will become
{ arg1: 'value', flag: true, "2": 'arg2', arg3: [ '1', '2', true ], arg4: 'value' };
Provides the list of basic terminal color palette.
The colors are: black
, red
, green
, yellow
, blue
, magenta
, cyan
, white
.
Each color has bright
(or intense
) and bg
(background) variants. E.g.
brightblue
, redbg
, intenseredbg
.
Additionally:
gray
is synonim forintenseblack
.def
- default foreground.defbg
, - default background.reset
- reset all styles.
var clr = require( 'App/CliColors' );
var clr = require( 'App/CliColors' );
console.log( clr.blue, clr.greenbg, 'blue on green background',
clr.def, 'default on green background',
clr.reset, 'default' );
Borislav Peev (borislav.asdf at gmail dot com)