molly-file
Version:
molly-file is a free and opensource
134 lines (107 loc) • 4.92 kB
JavaScript
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
const fetch = require('molly-fetch');
const rdl = require('readline');
const http = require('http');
const fs = require('fs');
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
function multiwrite( chunk, ...output ){
for( let out of output ){
if( !out.writableEnded )
out.write(chunk)
}
}
function multiclose( chunk, ...output ){
for( let out of output ){
if( !out.writableEnded )
out.end(chunk)
}
}
function multipipe( input, ...output ){
input.on('data',(chunk)=>{
for( let out of output ) {
if( !out.writableEnded )
out.write(chunk)
}
});
input.on('close',()=>{
for( let out of output ) {
if( !out.writableEnded )
out.end()
}
});
input.on('error',()=>{
for( let out of output ) {
if( !out.writableEnded )
out.end()
}
});
}
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
function isChunkFinished( path ){
return new Promise(async(response,reject)=>{
function wait(time){
return new Promise((response,reject)=>{
setTimeout(response,time);
});
}
function getContentLength(){
return new Promise((response,reject)=>{
const itf = rdl.createInterface({
input: fs.createReadStream( path )
});
itf.on('line',(line)=>{
if( !line.length ) return itf.close();
if( (/content-length/gi).test(line) )
response( +line.match(/\d+/gi)[0] )
});
itf.on('close',()=>{ response(0) });
});
}
let prev = fs.statSync(path).size;
let size = await getContentLength();
let i=0; while( true ){
const n_prev = fs.statSync(path).size;
if( !size || !prev ) return reject();
if( size < prev ) return response();
if( i > 4 ) return reject();
if( prev == n_prev ) i++;
await wait(1000);
prev = n_prev;
}
});
}
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/
module.exports = function(obj,cli){
function send( res ){
const wrt = fs.createWriteStream( obj.path );
const status = http.STATUS_CODES[res.status];
multiwrite(`${obj.ptr} ${res.status} ${status}\r\n`,cli,wrt);
for( const x of Object.keys( res.headers ) ){
if( (new RegExp('transfer-encoding','gi')).test(x) ) continue;
if( Array.isArray(res.headers[x]) ) for( const y of res.headers[x] )
multiwrite(`${x}: ${res.headers[x][y]}\r\n`,cli,wrt);
else multiwrite(`${x}: ${res.headers[x]}\r\n`, cli,wrt);
} multiwrite('\r\n',cli,wrt); multipipe(res.data,cli,wrt);
}
function end( res ){
const status = http.STATUS_CODES[404];
cli.write(`${obj.ptr} 404 ${status}\r\n`);
cli.write('contet-type: text/plain\r\n');
cli.end('\r\nurl not supported');
}
function str(){
fetch(obj).then(res=>{ send(res) }).catch(rej=>{
try {
if( rej.headers['range'] && !(/text/i).test(rej.headers['content-type']) )
rej.status = 100; send(rej);
} catch(e) { end() }
})
}
if( !fs.existsSync( obj.path ) ){
fs.writeFileSync( obj.path,'' ); return str();
} isChunkFinished(obj.path).then(()=>{
const rdb = fs.createReadStream(obj.path);
rdb.pipe(cli);
}).catch(()=>{ str() });
}
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/