function Server (opts) { 
	let server = this;
	server.send = send;
	let isBusy = true;
	
	let queue = [];
	if (!!opts.dir) {
		try {
			fs.mkdirSync(opts.dir); // default './outbox'
		} catch(err) {
			if (err.code != 'EEXIST') 
				throw err;
		}	
	
		queue = fs.readdirSync(opts.dir)
			.map(function (f) { 
				return {
					id: f.split('.')[0], 
					event: f.split('.')[1], 
					data: fs.readFileSync(`${opts.dir}/${f}`)
				};
			})
			.map(function (msg) { 
				try { 
					msg.data = JSON.parse(msg.data);
				} catch (err) { 
					server.emit('error', 'Error on parse ${msg.id}: ' + err.message); 
					msg.data = ''
				}; 
				return msg;
			})
			.filter((msg) => !!msg.data);	
		queue.add = function (msg) {
			this.push(msg);
			fs.writeFileSync(`${opts.dir}/${msg.id}.${msg.event}`, JSON.stringify(msg.data), {'flags': 'a'});
		}

	} else {
		queue.add = function (msg) {
			this.push(msg);
		}
	}

	function send(event, data, id) {
		queue.add({event, data, id: id || genId()});
		if (server.next)
			server.next();
	}

	let netServer = net.createServer(function(socket){
		isBusy = false;
		server.next = next;
		server.emit('connection', opts.id);
		next();
		
		function next() {
			if (isBusy)
				return;

			isBusy = true;

			if (queue.length == 0) 
				return (isBusy = false);
	
			if (socket)
				socket.write((!!opts.cipher ? encode(JSON.stringify(queue[0]), opts.cipher, opts.password) : JSON.stringify(queue[0])) + '|', () => { 
					server.emit('send', queue[0]);
					queue.shift();
					isBusy = false; 
					next(); 
				});
		}
		
		let buffer = '';
		socket.on('data', function(chunk) {
			buffer += chunk;
			if (buffer.indexOf('|') == -1)
				return;
	
			let msgs = buffer.split('|');
			buffer = msgs.pop();

			msgs.forEach(function(packet){

				let msg;
				try { 
					msg = JSON.parse(!!opts.cipher ? decode(packet, opts.cipher, opts.password) : packet);
				} catch(err) { 
					return socket.emit('error', err);
				}	
				server.emit('receive', msg);
				
				if (msg.event == 'ACK' && !!opts.dir) {
					fs.unlink(`${opts.dir}/${msg.data.id}.${msg.data.event}`, (err) => err ? console.log(err) : null);
					return;
				}
		
				server.emit(msg.event, msg.data, msg.id);
			});	
		});
	
		socket.on('close', () => { 
			server.emit('disconnection', opts.id) 
			socket = undefined; 
		});
	
		socket.on('error', (err) => server.emit('error', err));
	});
	netServer.maxConnections = 1;
	netServer.listen(opts.port, (err) => console.log(err ? err : 'Listen on ' + opts.port));	
	netServer.on('close', () => process.exit(1));
}
function Server (opts) { 
	let server = this;
	server.send = send;
	let isBusy = true;
	
	let queue = [];
	if (!!opts.dir) {
		try {
			fs.mkdirSync(opts.dir); 
		} catch(err) {
			if (err.code != 'EEXIST') 
				throw err;
		}	
	
		queue = fs.readdirSync(opts.dir)
			.map(function (f) { 
				return {
					id: f.split('.')[0], 
					event: f.split('.')[1], 
					data: fs.readFileSync(`${opts.dir}/${f}`)
				};
			})
			.map(function (msg) { 
				try { 
					msg.data = JSON.parse(msg.data);
				} catch (err) { 
					server.emit('error', 'Error on parse ${msg.id}: ' + err.message); 
					msg.data = ''
				}; 
				return msg;
			})
			.filter((msg) => !!msg.data);	
		queue.add = function (msg) {
			this.push(msg);
			fs.writeFileSync(`${opts.dir}/${msg.id}.${msg.event}`, JSON.stringify(msg.data), {'flags': 'a'});
		}

	} else {
		queue.add = function (msg) {
			this.push(msg);
		}
	}

	function send(event, data, id) {
		queue.add({event, data, id: id || genId()});
		if (server.next)
			server.next();
	}

	let netServer = net.createServer(function(socket){
		isBusy = false;
		server.next = next;
		server.emit('connection', opts.id);
		next();
		
		function next() {
			if (isBusy)
				return;

			isBusy = true;

			if (queue.length == 0) 
				return (isBusy = false);
	
			if (socket)
				socket.write((!!opts.cipher ? encode(JSON.stringify(queue[0]), opts.cipher, opts.password) : JSON.stringify(queue[0])) + '|', () => { 
					server.emit('send', queue[0]);
					queue.shift();
					isBusy = false; 
					next(); 
				});
		}
		
		let buffer = '';
		socket.on('data', function(chunk) {
			buffer += chunk;
			if (buffer.indexOf('|') == -1)
				return;
	
			let msgs = buffer.split('|');
			buffer = msgs.pop();

			msgs.forEach(function(packet){

				let msg;
				try { 
					msg = JSON.parse(!!opts.cipher ? decode(packet, opts.cipher, opts.password) : packet);
				} catch(err) { 
					return socket.emit('error', err);
				}	
				server.emit('receive', msg);
				
				if (msg.event == 'ACK' && !!opts.dir) {
					fs.unlink(`${opts.dir}/${msg.data.id}.${msg.data.event}`, (err) => err ? console.log(err) : null);
					return;
				}
		
				server.emit(msg.event, msg.data, msg.id);
			});	
		});
	
		socket.on('close', () => { 
			server.emit('disconnection', opts.id) 
			socket = undefined; 
		});
	
		socket.on('error', (err) => server.emit('error', err));
	});
	netServer.maxConnections = 1;
	netServer.listen(opts.port, (err) => console.log(err ? err : 'Listen on ' + opts.port));	
	netServer.on('close', () => process.exit(1));
}
function Server ( opts ) { let server = this ; server . send = send ; let isBusy = true ; let queue = [ ] ; if ( ! ! opts . dir ) { try { fs . mkdirSync ( opts . dir ) ; // default './outbox' } catch ( err ) { if ( err . code != 'EEXIST' ) throw err ; } queue = fs . readdirSync ( opts . dir ) . map ( function ( f ) { return { id : f . split ( '.' ) [ 0 ] , event : f . split ( '.' ) [ 1 ] , data : fs . readFileSync ( ` ${ opts . dir } ${ f } ` ) } ; } ) . map ( function ( msg ) { try { msg . data = JSON . parse ( msg . data ) ; } catch ( err ) { server . emit ( 'error' , 'Error on parse ${msg.id}: ' + err . message ) ; msg . data = '' } ; return msg ; } ) . filter ( ( msg ) => ! ! msg . data ) ; queue . add = function ( msg ) { this . push ( msg ) ; fs . writeFileSync ( ` ${ opts . dir } ${ msg . id } ${ msg . event } ` , JSON . stringify ( msg . data ) , { 'flags' : 'a' } ) ; } } else { queue . add = function ( msg ) { this . push ( msg ) ; } } function send ( event , data , id ) { queue . add ( { event , data , id : id || genId ( ) } ) ; if ( server . next ) server . next ( ) ; } let netServer = net . createServer ( function ( socket ) { isBusy = false ; server . next = next ; server . emit ( 'connection' , opts . id ) ; next ( ) ; function next ( ) { if ( isBusy ) return ; isBusy = true ; if ( queue . length == 0 ) return ( isBusy = false ) ; if ( socket ) socket . write ( ( ! ! opts . cipher ? encode ( JSON . stringify ( queue [ 0 ] ) , opts . cipher , opts . password ) : JSON . stringify ( queue [ 0 ] ) ) + '|' , ( ) => { server . emit ( 'send' , queue [ 0 ] ) ; queue . shift ( ) ; isBusy = false ; next ( ) ; } ) ; } let buffer = '' ; socket . on ( 'data' , function ( chunk ) { buffer += chunk ; if ( buffer . indexOf ( '|' ) == - 1 ) return ; let msgs = buffer . split ( '|' ) ; buffer = msgs . pop ( ) ; msgs . forEach ( function ( packet ) { let msg ; try { msg = JSON . parse ( ! ! opts . cipher ? decode ( packet , opts . cipher , opts . password ) : packet ) ; } catch ( err ) { return socket . emit ( 'error' , err ) ; } server . emit ( 'receive' , msg ) ; if ( msg . event == 'ACK' && ! ! opts . dir ) { fs . unlink ( ` ${ opts . dir } ${ msg . data . id } ${ msg . data . event } ` , ( err ) => err ? console . log ( err ) : null ) ; return ; } server . emit ( msg . event , msg . data , msg . id ) ; } ) ; } ) ; socket . on ( 'close' , ( ) => { server . emit ( 'disconnection' , opts . id ) socket = undefined ; } ) ; socket . on ( 'error' , ( err ) => server . emit ( 'error' , err ) ) ; } ) ; netServer . maxConnections = 1 ; netServer . listen ( opts . port , ( err ) => console . log ( err ? err : 'Listen on ' + opts . port ) ) ; netServer . on ( 'close' , ( ) => process . exit ( 1 ) ) ; }
opts = {port, cipher, password, dir}
opts = { port cipher password dir }