UNPKG

molly-file

Version:
134 lines (107 loc) 4.92 kB
/*--────────────────────────────────────────────────────────────────────────────────────────────--*/ 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() }); } /*--────────────────────────────────────────────────────────────────────────────────────────────--*/