BotanSS/utils/CondStream.js

134 lines
2.3 KiB
JavaScript
Raw Normal View History

2016-02-19 15:44:03 +00:00
"use strict";
2016-07-04 03:56:03 +00:00
const Dragonfly = global.Dragonfly;
2016-02-19 15:44:03 +00:00
2016-07-04 03:56:03 +00:00
const fs = require( "fs" );
const path = require( "path" );
const crypto = require( "crypto" );
const ReadStream = require( "stream" ).Readable;
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
class ConditionalStream extends String
2015-07-23 09:15:24 +00:00
{
2016-02-19 15:44:03 +00:00
constructor( tmpPath, triggerLimit )
2015-07-23 09:15:24 +00:00
{
2016-02-19 15:44:03 +00:00
super();
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
if( !tmpPath )
{
throw new Error( "Temp path is not defined" );
}
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
this.size = 0;
this.limit = triggerLimit * 1024;
this.stream = false;
this.hexData = "";
this.tmpPath = tmpPath;
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
this.file = false;
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
this.__discard = false;
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
this.__ended = false;
this.__finished = false;
}
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
write( data )
2015-07-23 09:15:24 +00:00
{
2016-02-19 15:44:03 +00:00
this.size += data.length;
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
if( this.stream )
{
this.hexData = false;
this.stream.write( data );
return;
}
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
this.hexData += data.toString( "hex" );
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
// Trigger
if( this.limit < this.size )
{
this.file = path.join( this.tmpPath, "ss_" + crypto.randomBytes( 8 ).toString( "hex" ) );
this.stream = fs.createWriteStream( this.file, { mode: "0600" } );
this.stream.addListener( "finish", this.__end.bind( this ) );
this.stream.write( this.hexData, "hex" );
}
2015-07-23 09:15:24 +00:00
}
2016-02-19 15:44:03 +00:00
end( handler )
2015-07-23 09:15:24 +00:00
{
2016-02-19 15:44:03 +00:00
if( this.stream )
{
2016-07-04 03:56:03 +00:00
this.stream.addListener( "close", () => {
this.__finished = true;
handler( this );
2016-02-19 15:44:03 +00:00
} );
this.stream.end();
}
else
2015-07-23 09:15:24 +00:00
{
2016-07-04 03:56:03 +00:00
setTimeout( () => {
this.__finished = true;
handler( this );
2016-02-19 15:44:03 +00:00
} , 0 );
}
2015-07-23 09:15:24 +00:00
}
2016-02-19 15:44:03 +00:00
discard()
2015-07-23 09:15:24 +00:00
{
2016-02-19 15:44:03 +00:00
this.__discard = true;
if( this.__finished && this.file )
2015-07-23 09:15:24 +00:00
{
2016-07-04 03:56:03 +00:00
fs.unlink( this.file, ( e ) =>
2016-02-19 15:44:03 +00:00
{
2016-07-04 03:56:03 +00:00
Dragonfly.Debug( "Client Data Closed: " + this.file );
if( this.__error ) throw new Error( this.__error );
2016-02-19 15:44:03 +00:00
} );
}
2015-07-23 09:15:24 +00:00
}
2016-02-19 15:44:03 +00:00
toString( enc )
2015-07-23 09:15:24 +00:00
{
2016-02-19 15:44:03 +00:00
if( this.stream )
{
this.discard();
this.__error = "Received data is too large to process";
}
return new Buffer( this.hexData, "hex" ).toString( enc );
2015-07-23 09:15:24 +00:00
}
2016-02-19 15:44:03 +00:00
resultStream()
{
if( !this.__finished ) throw new Error( "Data is not finished yet" );
if( this.__discard ) throw new Error( "Data is discarded" );
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
if( this.stream )
{
var rt = fs.createReadStream( this.file );
2016-07-04 03:56:03 +00:00
rt.addListener( "close", () => this.discard() );
2016-02-19 15:44:03 +00:00
return rt;
}
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
var st = new ReadStream();
st._read = function(){};
2015-07-23 09:15:24 +00:00
2016-07-04 03:56:03 +00:00
setTimeout( () => {
st.push( this.hexData, "hex" );
2016-02-19 15:44:03 +00:00
st.push( null );
}, 0 );
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
return st;
}
2015-07-23 09:15:24 +00:00
2016-02-19 15:44:03 +00:00
__end()
{
this.__finished = true;
if( this.__discard ) this.discard();
}
}
2015-07-23 09:15:24 +00:00
module.exports = ConditionalStream;