Initial commit
This commit is contained in:
commit
d3e8b0efa7
122
Dragonfly.js
Normal file
122
Dragonfly.js
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
var util = require('util');
|
||||||
|
|
||||||
|
/*{{{ Private methods */
|
||||||
|
// Months
|
||||||
|
var mon = [ '01', '02', '03', '04', '05', '06', '07', '08', '09', '10', '11', '12' ];
|
||||||
|
|
||||||
|
function padZero( num )
|
||||||
|
{
|
||||||
|
if( num < 10 ) return "0" + String( num );
|
||||||
|
return String( num );
|
||||||
|
}
|
||||||
|
|
||||||
|
function logDate( date )
|
||||||
|
{
|
||||||
|
return "[ " + date.getFullYear()
|
||||||
|
+ "-" + mon[ date.getMonth() ]
|
||||||
|
+ "-" + padZero( date.getDate() )
|
||||||
|
+ " " + padZero( date.getHours() )
|
||||||
|
+ ":" + padZero( date.getMinutes() )
|
||||||
|
+ ":" + padZero( date.getSeconds() )
|
||||||
|
+ " ] ";
|
||||||
|
}
|
||||||
|
/*}}}*/
|
||||||
|
// Logger
|
||||||
|
function Dragonfly()
|
||||||
|
{
|
||||||
|
// Static properties
|
||||||
|
Dragonfly.currentSphere = 10;
|
||||||
|
|
||||||
|
Dragonfly.Spheres = {
|
||||||
|
THERMO: 30
|
||||||
|
, STRATO: 20
|
||||||
|
, HYDRO: 10
|
||||||
|
, LITHO: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
Dragonfly.Visibility = {
|
||||||
|
VISIBLE: 9
|
||||||
|
, VH8: 8, VH7: 7, VH6: 6
|
||||||
|
, HIDDEN: 5
|
||||||
|
, HU4: 4, HU3: 3, HU2: 2
|
||||||
|
, UNSEEN: 1
|
||||||
|
};
|
||||||
|
|
||||||
|
// Bind prototype functions
|
||||||
|
for( var i in Dragonfly.prototype )
|
||||||
|
{
|
||||||
|
Dragonfly[i] = this[i].bind( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
var cluster = require("cluster");
|
||||||
|
this.ptag = "[ " + ( cluster.isMaster ? "M" : "S" ) + ":" + process.pid + " ] ";
|
||||||
|
|
||||||
|
this.Info( "Dragonfly ready.", Dragonfly.Visibility.VISIBLE );
|
||||||
|
}
|
||||||
|
|
||||||
|
Dragonfly.prototype.Info = function( mesg, visibility )
|
||||||
|
{
|
||||||
|
this.Log( mesg, Dragonfly.Spheres.THERMO, visibility );
|
||||||
|
};
|
||||||
|
|
||||||
|
Dragonfly.prototype.Warning = function( mesg, visibility )
|
||||||
|
{
|
||||||
|
this.Log( mesg, Dragonfly.Spheres.STRATO, visibility );
|
||||||
|
};
|
||||||
|
|
||||||
|
Dragonfly.prototype.Error = function( mesg, visibility )
|
||||||
|
{
|
||||||
|
this.Log( mesg, Dragonfly.Spheres.HYDRO, visibility );
|
||||||
|
};
|
||||||
|
|
||||||
|
Dragonfly.prototype.Debug = function( mesg, visibility )
|
||||||
|
{
|
||||||
|
this.Log( mesg, Dragonfly.Spheres.LITHO, visibility );
|
||||||
|
};
|
||||||
|
|
||||||
|
Dragonfly.prototype.Log = function( mesg, sphere, visibility )
|
||||||
|
{
|
||||||
|
if( isNaN( sphere ) ) sphere = Dragonfly.Spheres.LITHO;
|
||||||
|
|
||||||
|
visibility = Number( visibility );
|
||||||
|
isNaN( visibility ) && ( visibility = 0 );
|
||||||
|
|
||||||
|
sphere += visibility;
|
||||||
|
|
||||||
|
var write = true;
|
||||||
|
if( Dragonfly.currentSphere < sphere )
|
||||||
|
{
|
||||||
|
write = ( Dragonfly.currentSphere % 10 < sphere % 10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writeline if yes
|
||||||
|
write && this.writeLine( mesg );
|
||||||
|
};
|
||||||
|
|
||||||
|
Dragonfly.prototype.writeLine = function ()
|
||||||
|
{
|
||||||
|
for( var i in arguments )
|
||||||
|
{
|
||||||
|
if( typeof( arguments[i] ) == "string" )
|
||||||
|
{
|
||||||
|
this.__log( arguments[i] );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var lines = util.inspect( arguments[i] ).split("\n");
|
||||||
|
for( var j in lines )
|
||||||
|
{
|
||||||
|
this.__log( lines[j] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Dragonfly.prototype.__log = function ( line )
|
||||||
|
{
|
||||||
|
console.log( this.ptag + logDate( new Date() ) + line );
|
||||||
|
};
|
||||||
|
|
||||||
|
new Dragonfly();
|
||||||
|
|
||||||
|
global.Dragonfly = Dragonfly;
|
19
errors/FatalError.js
Normal file
19
errors/FatalError.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
function error( msg )
|
||||||
|
{
|
||||||
|
this.name = "Fatal Error";
|
||||||
|
this.message = msg;
|
||||||
|
|
||||||
|
var e = new Error();
|
||||||
|
e = e.stack.split( "\n" );
|
||||||
|
e[0] = this.name;
|
||||||
|
e[1] = "";
|
||||||
|
|
||||||
|
this.stack = e.join( "\n" );
|
||||||
|
}
|
||||||
|
|
||||||
|
error.prototype.toString = function()
|
||||||
|
{
|
||||||
|
return this.name + " " + this.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = error;
|
12
errors/InternalServerError.js
Normal file
12
errors/InternalServerError.js
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
function error( msg )
|
||||||
|
{
|
||||||
|
this.name = "Internel Server Error";
|
||||||
|
this.message = msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
error.prototype.toString = function()
|
||||||
|
{
|
||||||
|
return this.name + " " + this.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = error;
|
67
net/AppDomain.js
Normal file
67
net/AppDomain.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
var Dragonfly = global.Dragonfly;
|
||||||
|
|
||||||
|
var domain = require('domain');
|
||||||
|
var FatalError = require( '../errors/FatalError' );
|
||||||
|
|
||||||
|
// Message is hardcoded to prevent further exceptions occured
|
||||||
|
// This function must be bug-free
|
||||||
|
function server500( response, e )
|
||||||
|
{
|
||||||
|
response.statusCode = 500;
|
||||||
|
response.setHeader( 'Content-Type', 'text/plain' );
|
||||||
|
response.end( e.message );
|
||||||
|
}
|
||||||
|
|
||||||
|
function serverHandle( server, request, response, rHandle )
|
||||||
|
{
|
||||||
|
var d = domain.create();
|
||||||
|
|
||||||
|
d.addListener( 'error', function( e ) {
|
||||||
|
Dragonfly.Error( e.stack );
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var killtimer = setTimeout( function()
|
||||||
|
{
|
||||||
|
process.exit(1);
|
||||||
|
}, 3000);
|
||||||
|
killtimer.unref();
|
||||||
|
|
||||||
|
server.close();
|
||||||
|
|
||||||
|
GLOBAL.X_SERVER_CLUSTER.worker.disconnect();
|
||||||
|
|
||||||
|
server500( response, e );
|
||||||
|
}
|
||||||
|
catch( ex )
|
||||||
|
{
|
||||||
|
Dragonfly.Error( ex.stack );
|
||||||
|
process.exit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
d.add( request );
|
||||||
|
d.add( response );
|
||||||
|
|
||||||
|
d.run( function() {
|
||||||
|
rHandle( request, response );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Construncor
|
||||||
|
function AppDomain( handler, port, cluster )
|
||||||
|
{
|
||||||
|
var http = require('http');
|
||||||
|
var server = http.createServer(
|
||||||
|
function(req, res) {
|
||||||
|
serverHandle( server, req, res, handler );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
server.listen( port );
|
||||||
|
Dragonfly.Info( "Listening on: " + port, Dragonfly.Visibility.VISIBLE );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = AppDomain;
|
111
net/Router.js
Normal file
111
net/Router.js
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
var Dragonfly = global.Dragonfly;
|
||||||
|
var FatalError = require( '../errors/FatalError.js' );
|
||||||
|
|
||||||
|
var MaxRedirect = 10;
|
||||||
|
|
||||||
|
var stripURI = function( url )
|
||||||
|
{
|
||||||
|
return url.replace( /\/+/g, '/' ).replace( /^\//, '' );
|
||||||
|
};
|
||||||
|
|
||||||
|
var RelayPoint = function( uri, internal )
|
||||||
|
{
|
||||||
|
this.direct = Boolean(
|
||||||
|
typeof internal !== 'undefined' ? internal : false
|
||||||
|
);
|
||||||
|
|
||||||
|
this.value = internal ? uri : stripURI( uri );
|
||||||
|
};
|
||||||
|
|
||||||
|
var Router = function( http )
|
||||||
|
{
|
||||||
|
this.HTTP = http;
|
||||||
|
this.routes = {};
|
||||||
|
this.routable = true;
|
||||||
|
this.redirect_count = 0;
|
||||||
|
|
||||||
|
// Changed when routing
|
||||||
|
this.inputs = [];
|
||||||
|
this.routeObj = {};
|
||||||
|
this.reroute = false;
|
||||||
|
|
||||||
|
this.relaying = new RelayPoint( http.request.raw.url );
|
||||||
|
};
|
||||||
|
|
||||||
|
Router.prototype.addRoute = function( name, _route, _action, _status )
|
||||||
|
{
|
||||||
|
this.routes[ name ] = {
|
||||||
|
route: _route
|
||||||
|
, action: String( _action )
|
||||||
|
, status: Boolean(
|
||||||
|
typeof _status !== 'undefined' ? _status : true
|
||||||
|
)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Router.prototype.route = function()
|
||||||
|
{
|
||||||
|
if( MaxRedirect < this.redirect_count )
|
||||||
|
throw new FatalError( "Max redirection reached" );
|
||||||
|
|
||||||
|
this.redirect_count ++;
|
||||||
|
this.inputs[ this.inputs.length ] = this.relaying;
|
||||||
|
|
||||||
|
var currentRoute = this.relaying.value;
|
||||||
|
var r;
|
||||||
|
|
||||||
|
if( this.relaying.direct )
|
||||||
|
{
|
||||||
|
if( r = this.routes[ this.relaying.value ] )
|
||||||
|
{
|
||||||
|
this.routable = false;
|
||||||
|
this.setRoute( r );
|
||||||
|
return r.action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for( var i in this.routes )
|
||||||
|
{
|
||||||
|
r = this.routes[i];
|
||||||
|
if( r.route.constructor.prototype.exec )
|
||||||
|
{
|
||||||
|
var match = r.route.exec( currentRoute );
|
||||||
|
if( match )
|
||||||
|
{
|
||||||
|
// Set routable to false
|
||||||
|
this.routable = false;
|
||||||
|
this.setRoute( r, match );
|
||||||
|
return r.action;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.routable = false;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set Route
|
||||||
|
Router.prototype.setRoute = function( _route, _match )
|
||||||
|
{
|
||||||
|
this.routeObj = {
|
||||||
|
route: _route
|
||||||
|
, match: _match
|
||||||
|
, router: this.router
|
||||||
|
, inputs: this.inputs
|
||||||
|
|
||||||
|
// Re-route function
|
||||||
|
, reroute: function( target, direct )
|
||||||
|
{
|
||||||
|
Dragonfly.Log(
|
||||||
|
"Reroute: " + target
|
||||||
|
+ ( direct ? ", Direct" : "" )
|
||||||
|
);
|
||||||
|
this.relaying = new RelayPoint( target, direct );
|
||||||
|
this.routable = true;
|
||||||
|
this.reroute = true;
|
||||||
|
}.bind( this )
|
||||||
|
};
|
||||||
|
};
|
||||||
|
module.exports = Router;
|
100
net/WebFrame.js
Normal file
100
net/WebFrame.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
var Dragonfly = global.Dragonfly;
|
||||||
|
var FatalError = require( '../errors/FatalError.js' );
|
||||||
|
|
||||||
|
var Framework = function( garden )
|
||||||
|
{
|
||||||
|
this.HTTP = garden;
|
||||||
|
this.result = 0;
|
||||||
|
this.planted = false;
|
||||||
|
this.requestStr = "";
|
||||||
|
this.requestObj = {};
|
||||||
|
|
||||||
|
var Router = require( "./Router" );
|
||||||
|
this.router = new Router( garden );
|
||||||
|
this.router.addRoute( "404", false, "p404" );
|
||||||
|
|
||||||
|
this.handlers = {
|
||||||
|
"404": function()
|
||||||
|
{
|
||||||
|
this.HTTP.response.statusCode = 404;
|
||||||
|
this.result = "404 Not Found";
|
||||||
|
}.bind( this )
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Framework.prototype.run = function()
|
||||||
|
{
|
||||||
|
var _self = this;
|
||||||
|
|
||||||
|
var method = "GET";
|
||||||
|
if( this.HTTP.request.isPost )
|
||||||
|
{
|
||||||
|
this.HTTP.request.raw.addListener( "data", function( data )
|
||||||
|
{
|
||||||
|
_self.requestStr += data.toString();
|
||||||
|
})
|
||||||
|
this.HTTP.request.raw.addListener( "end", function()
|
||||||
|
{
|
||||||
|
_self.parseResult();
|
||||||
|
});
|
||||||
|
|
||||||
|
method = "POST";
|
||||||
|
}
|
||||||
|
|
||||||
|
Dragonfly.Info(
|
||||||
|
method + ": " + encodeURI( this.HTTP.request.raw.url )
|
||||||
|
+ " - " + this.HTTP.request.raw.headers["user-agent"]
|
||||||
|
, Dragonfly.Visibility.VISIBLE
|
||||||
|
);
|
||||||
|
|
||||||
|
if( method == "GET" ) _self.parseResult();
|
||||||
|
};
|
||||||
|
|
||||||
|
Framework.prototype.addHandler = function( name, method )
|
||||||
|
{
|
||||||
|
this.handlers[ name ] = method.bind( this );
|
||||||
|
};
|
||||||
|
|
||||||
|
Framework.prototype.parseResult = function()
|
||||||
|
{
|
||||||
|
while( this.router.routable )
|
||||||
|
{
|
||||||
|
var method = this.router.route();
|
||||||
|
if( method )
|
||||||
|
{
|
||||||
|
Dragonfly.Debug( "Call " + method );
|
||||||
|
|
||||||
|
if( this.handlers[ method ] )
|
||||||
|
{
|
||||||
|
this.handlers[ method ]( this.router.routeObj );
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FatalError( "Relay handler \"" + method + "\" is not defined" );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.plantResult();
|
||||||
|
};
|
||||||
|
|
||||||
|
Framework.prototype.plantResult = function()
|
||||||
|
{
|
||||||
|
if( !this.planted )
|
||||||
|
{
|
||||||
|
this.planted = true;
|
||||||
|
if( this.HTTP )
|
||||||
|
{
|
||||||
|
if( !( this.result instanceof Buffer ) )
|
||||||
|
{
|
||||||
|
this.result = String( this.result );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.HTTP.response.headers["Content-Length"] = this.result.length;
|
||||||
|
this.HTTP.response.write( this.result );
|
||||||
|
this.HTTP.response.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Framework;
|
41
net/http.js
Normal file
41
net/http.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
var Dragonfly = global.Dragonfly;
|
||||||
|
|
||||||
|
var HTTP = function( req, res )
|
||||||
|
{
|
||||||
|
var _self = this;
|
||||||
|
var canExit = true;
|
||||||
|
|
||||||
|
// Simple HTTP Model
|
||||||
|
this.response = {
|
||||||
|
statusCode: 200
|
||||||
|
, headers: {
|
||||||
|
'Content-Type': 'text/html'
|
||||||
|
}
|
||||||
|
, write: function( str ) { _self.response.content = str }
|
||||||
|
, writeLine: function( str ) { _self.response.content += str + "\n"; }
|
||||||
|
, end: function()
|
||||||
|
{
|
||||||
|
if( canExit )
|
||||||
|
{
|
||||||
|
canExit = false;
|
||||||
|
|
||||||
|
var rc = _self.response;
|
||||||
|
|
||||||
|
res.writeHead( rc.statusCode, rc.headers );
|
||||||
|
res.end( rc.content );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
, content: ''
|
||||||
|
, raw: res
|
||||||
|
};
|
||||||
|
|
||||||
|
this.request = {
|
||||||
|
uri: require('url').parse( req.url )
|
||||||
|
, isPost: ( req.method == 'POST' )
|
||||||
|
, remoteAddr: req.connection.remoteAddress
|
||||||
|
, raw: req
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = HTTP;
|
Loading…
Reference in New Issue
Block a user