Initial commit
This commit is contained in:
		
							
								
								
									
										84
									
								
								infrastructure.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								infrastructure.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
"use stict";
 | 
			
		||||
 | 
			
		||||
const cl = global.botanLoader;
 | 
			
		||||
 | 
			
		||||
const events = require( "events" );
 | 
			
		||||
const util = require( "util" );
 | 
			
		||||
 | 
			
		||||
var Infrastructure = function()
 | 
			
		||||
{
 | 
			
		||||
	events.EventEmitter.call( this );
 | 
			
		||||
	var _self = this;
 | 
			
		||||
 | 
			
		||||
	var __readyList = [];
 | 
			
		||||
	this.readyList = new Proxy( __readyList, {
 | 
			
		||||
 | 
			
		||||
		get: ( target, prop ) => Reflect.get( target, prop )
 | 
			
		||||
 | 
			
		||||
		, set: ( target, prop, value ) => {
 | 
			
		||||
 | 
			
		||||
			// Have to emit the event at next tick
 | 
			
		||||
			// due to error thrown from the handlers
 | 
			
		||||
			// hangs the process
 | 
			
		||||
			process.nextTick( () => {
 | 
			
		||||
				if( __readyList.every( ( v ) => v === true ) )
 | 
			
		||||
				{
 | 
			
		||||
					_self.isReady = true;
 | 
			
		||||
					_self.emit( "apis_ready", _self )
 | 
			
		||||
				}
 | 
			
		||||
			} );
 | 
			
		||||
 | 
			
		||||
			return Reflect.set( target, prop, value );
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
	} );
 | 
			
		||||
 | 
			
		||||
	this.APIs = {};
 | 
			
		||||
	this.isReady = true;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
util.inherits( Infrastructure, events.EventEmitter );
 | 
			
		||||
 | 
			
		||||
Infrastructure.prototype.callAPI = function( name )
 | 
			
		||||
{
 | 
			
		||||
	var _self = this;
 | 
			
		||||
 | 
			
		||||
	var propName = name.split( "." );
 | 
			
		||||
	propName = name[ name.length - 1 ];
 | 
			
		||||
 | 
			
		||||
	if( this.APIs[ propName ] ) return this.APIs[ propName ];
 | 
			
		||||
 | 
			
		||||
	var path = name.replace( ".", "/" );
 | 
			
		||||
 | 
			
		||||
	var API = cl.load( name );
 | 
			
		||||
 | 
			
		||||
	if( !API.create )
 | 
			
		||||
	{
 | 
			
		||||
		throw new Error( "API does not have support calling" );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var aclass = API.create( Array.prototype.slice.call( arguments, 1 ) );
 | 
			
		||||
 | 
			
		||||
	this.APIs[ propName ] = aclass;
 | 
			
		||||
 | 
			
		||||
	if( aclass.ready !== undefined )
 | 
			
		||||
	{
 | 
			
		||||
		this.isReady = false;
 | 
			
		||||
 | 
			
		||||
		var rList =  this.readyList;
 | 
			
		||||
		rList.push( aclass.ready || aclass );
 | 
			
		||||
 | 
			
		||||
		aclass.once( "ready", ( e ) => rList[ rList.indexOf( e ) ] = true );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return aclass;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Infrastructure.prototype.Ready = function( callback )
 | 
			
		||||
{
 | 
			
		||||
	var _self = this;
 | 
			
		||||
	if( this.isReady ) callback();
 | 
			
		||||
	else this.once( "apis_ready", () => callback() );
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
module.exports = Infrastructure;
 | 
			
		||||
							
								
								
									
										22
									
								
								redisclient.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								redisclient.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
			
		||||
const cl = global.botanLoader;
 | 
			
		||||
const Dragonfly = global.Dragonfly;
 | 
			
		||||
 | 
			
		||||
const Redis = require( "redis" );
 | 
			
		||||
 | 
			
		||||
const SessConf = cl.load( "config.sx.modular.session" );
 | 
			
		||||
 | 
			
		||||
var Client = Redis.createClient(
 | 
			
		||||
	SessConf.config.port
 | 
			
		||||
	, SessConf.config.host
 | 
			
		||||
	, SessConf.config.options
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
Client.addListener( "error", ( e ) => { throw e; } );
 | 
			
		||||
 | 
			
		||||
Client.select( SessConf.config.database, function( err, message )
 | 
			
		||||
{
 | 
			
		||||
	if( err ) throw err; 
 | 
			
		||||
	Dragonfly.Info( "[Session] Database connected. Ready." );
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = Client;
 | 
			
		||||
							
								
								
									
										152
									
								
								session.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										152
									
								
								session.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,152 @@
 | 
			
		||||
"use strict";
 | 
			
		||||
 | 
			
		||||
const cl = global.botanLoader;
 | 
			
		||||
const Dragonfly = global.Dragonfly;
 | 
			
		||||
 | 
			
		||||
const util = require( "util" );
 | 
			
		||||
const EventEmitter = require( "events" ).EventEmitter;
 | 
			
		||||
 | 
			
		||||
const Client = cl.load( "botansx.modular.redisclient" );
 | 
			
		||||
const rand = cl.load( "botansx.utils.random" );
 | 
			
		||||
const SessConf = cl.load( "config.sx.modular.session" );
 | 
			
		||||
 | 
			
		||||
class SessionEventArgs
 | 
			
		||||
{
 | 
			
		||||
	constructor( message )
 | 
			
		||||
	{
 | 
			
		||||
		this.message = message;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Session extends EventEmitter
 | 
			
		||||
{
 | 
			
		||||
	static create( args )
 | 
			
		||||
	{
 | 
			
		||||
		if( !args ) args = [];
 | 
			
		||||
		return new Session( args[0], args[1] );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	constructor( hash, prefix, noIdReset )
 | 
			
		||||
	{
 | 
			
		||||
		super();
 | 
			
		||||
		var _self = this;
 | 
			
		||||
 | 
			
		||||
		if( hash && prefix )
 | 
			
		||||
			hash = hash.replace( new RegExp( "^" + prefix + "\\." ), "" );
 | 
			
		||||
 | 
			
		||||
		prefix = prefix ? prefix + "." : "";
 | 
			
		||||
 | 
			
		||||
		this.id = prefix + hash;
 | 
			
		||||
		this.ready = false;
 | 
			
		||||
		this.exists = false;
 | 
			
		||||
 | 
			
		||||
		Client.HGETALL( this.id, function( err, obj )
 | 
			
		||||
		{
 | 
			
		||||
			if( err ) throw err;
 | 
			
		||||
 | 
			
		||||
			if( _self.exists = !!obj )
 | 
			
		||||
			{
 | 
			
		||||
				_self.__sess = obj;
 | 
			
		||||
			}
 | 
			
		||||
			// Auto reset the session id if no match
 | 
			
		||||
			else if( !noIdReset )
 | 
			
		||||
			{
 | 
			
		||||
				_self.id = prefix + rand.uuid();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			_self.ready = true;
 | 
			
		||||
			_self.emit( "ready", _self );
 | 
			
		||||
		} );
 | 
			
		||||
 | 
			
		||||
		this.__sess = {};
 | 
			
		||||
		this.__emitOk = ( e, m ) => {
 | 
			
		||||
			_self.__emit( e, "set", new SessionEventArgs( m ) );
 | 
			
		||||
		};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	__emit( err, EventName, SessionArgs )
 | 
			
		||||
	{
 | 
			
		||||
		if( err ) throw err;
 | 
			
		||||
		this.emit( EventName || "set", this, SessionArgs );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	// Spawn session with specified id
 | 
			
		||||
	spawn( expire, handler )
 | 
			
		||||
	{
 | 
			
		||||
		var ttl = ( expire === undefined ? SessConf.ttl : expire ) + 0;
 | 
			
		||||
		this.__sess[ "lifespan" ] = ttl;
 | 
			
		||||
 | 
			
		||||
		var _self = this;
 | 
			
		||||
		Client.multi()
 | 
			
		||||
			.HSET( this.id, "spawn", new Date() )
 | 
			
		||||
			.HSET( this.id, "lifespan", ttl )
 | 
			
		||||
			.EXPIRE( this.id, ttl )
 | 
			
		||||
			.exec( handler || this.__emitOk );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	destroy( handler )
 | 
			
		||||
	{
 | 
			
		||||
		this.__sess = {};
 | 
			
		||||
		Client.DEL( this.id, handler || this.__emitOk );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	set( name, val )
 | 
			
		||||
	{
 | 
			
		||||
		this.__sess[ name ] = val;
 | 
			
		||||
		Client.HSET( this.id, name, val, this.__emitOk );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get( name )
 | 
			
		||||
	{
 | 
			
		||||
		return this.__sess[ name ];
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Get value asynchronously
 | 
			
		||||
	aget( name, handler )
 | 
			
		||||
	{
 | 
			
		||||
		var _self = this;
 | 
			
		||||
		Client.HGET(
 | 
			
		||||
			this.id, name
 | 
			
		||||
			, function( err, rep )
 | 
			
		||||
			{
 | 
			
		||||
				_self.__emitOk( err );
 | 
			
		||||
				_self.__sess[ name ] = rep;
 | 
			
		||||
				handler && handler( rep );
 | 
			
		||||
			}
 | 
			
		||||
		);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	remove( name )
 | 
			
		||||
	{
 | 
			
		||||
		delete this.__sess[ name ];
 | 
			
		||||
		Client.HDEL( this.id, name, this.__emitOk );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	expire( seconds )
 | 
			
		||||
	{
 | 
			
		||||
		// expire > lifespan > SessConf.ttl
 | 
			
		||||
		var ttl = ( seconds === undefined
 | 
			
		||||
			? ( ( this.__sess[ "lifespan" ] === undefined )
 | 
			
		||||
				? SessConf.ttl
 | 
			
		||||
				: this.__sess[ "lifespan" ]
 | 
			
		||||
			) : seconds ) + 0
 | 
			
		||||
		;
 | 
			
		||||
 | 
			
		||||
		this.__sess[ "lifespan" ] = ttl;
 | 
			
		||||
 | 
			
		||||
		Client.multi()
 | 
			
		||||
			.HSET( this.id, "lifespan", ttl )
 | 
			
		||||
			.EXPIRE( this.id, ttl, this.__emitOk )
 | 
			
		||||
			.exec( this.__emitOk );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	get busy()
 | 
			
		||||
	{
 | 
			
		||||
		return 0 < ( Client.command_queue.length + Client.offline_queue.length );
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Session.SessionEventArgs = SessionEventArgs;
 | 
			
		||||
 | 
			
		||||
module.exports = Session;
 | 
			
		||||
		Reference in New Issue
	
	Block a user