const fs = require('fs') const request = require('request') const exec = require('child_process').exec const spawn = require('child_process').spawn const isWindows = (process.platform === 'win32' || process.platform === 'win64') process.send = process.send || function () {}; if(!process.argv[2] || !process.argv[3]){ return writeToStderr('Missing FFMPEG Command String or no command operator') } var jsonData = JSON.parse(fs.readFileSync(process.argv[3],'utf8')) const ffmpegAbsolutePath = process.argv[2].trim() const ffmpegCommandString = jsonData.cmd const rawMonitorConfig = jsonData.rawMonitorConfig const stdioPipes = jsonData.pipes || [] var newPipes = [] var stdioWriters = []; var writeToStderr = function(text){ try{ process.stderr.write(Buffer.from(`${text}`, 'utf8' )) // stdioWriters[2].write(Buffer.from(`${new Error('writeToStderr').stack}`, 'utf8' )) }catch(err){ } // fs.appendFileSync('/home/Shinobi/test.log',text + '\n','utf8') } const buildMonitorUrl = function(e,noPath){ var authd = '' var url if(e.details.muser&&e.details.muser!==''&&e.host.indexOf('@')===-1) { e.username = e.details.muser e.password = e.details.mpass authd = e.details.muser+':'+e.details.mpass+'@' } if(e.port==80&&e.details.port_force!=='1'){e.porty=''}else{e.porty=':'+e.port} url = e.protocol+'://'+authd+e.host+e.porty if(noPath !== true)url += e.path return url } // [CTRL] + [C] = exit process.on('uncaughtException', function (err) { writeToStderr('Uncaught Exception occured!'); writeToStderr(err.stack); }); const exitAction = function(){ try{ if(isWindows){ spawn("taskkill", ["/pid", cameraProcess.pid, '/f', '/t']) }else{ process.kill(-cameraProcess.pid) } }catch(err){ } } process.on('SIGTERM', exitAction); process.on('SIGINT', exitAction); process.on('exit', exitAction); for(var i=0; i < stdioPipes; i++){ switch(i){ case 0: newPipes[i] = 'pipe' break; case 1: newPipes[i] = 1 break; case 2: newPipes[i] = 2 break; case 3: stdioWriters[i] = fs.createWriteStream(null, {fd: i, end:false}); if(rawMonitorConfig.details.detector === '1' && rawMonitorConfig.details.detector_pam === '1'){ newPipes[i] = 'pipe' }else{ newPipes[i] = stdioWriters[i] } break; case 5: stdioWriters[i] = fs.createWriteStream(null, {fd: i, end:false}); newPipes[i] = 'pipe' break; default: stdioWriters[i] = fs.createWriteStream(null, {fd: i, end:false}); newPipes[i] = stdioWriters[i] break; } } stdioWriters.forEach((writer)=>{ writer.on('error', (err) => { writeToStderr(err.stack); }); }) writeToStderr(JSON.stringify(ffmpegCommandString)) var cameraProcess = spawn(ffmpegAbsolutePath,ffmpegCommandString,{detached: true,stdio:newPipes}) cameraProcess.on('close',()=>{ writeToStderr('Process Closed') stdioWriters.forEach((writer)=>{ writer.end() }) process.exit(); }) cameraProcess.stdio[5].on('data',(data)=>{ stdioWriters[5].write(data) }) writeToStderr('Thread Opening') if(rawMonitorConfig.details.detector === '1' && rawMonitorConfig.details.detector_pam === '1'){ try{ const attachPamDetector = require(__dirname + '/detector.js')(jsonData,stdioWriters[3]) attachPamDetector(cameraProcess,(err)=>{ writeToStderr(err) }) }catch(err){ writeToStderr(err.stack) } } if(rawMonitorConfig.type === 'jpeg'){ var recordingSnapRequest var recordingSnapper var errorTimeout var errorCount = 0 var capture_fps = parseFloat(rawMonitorConfig.details.sfps || 1) if(isNaN(capture_fps))capture_fps = 1 try{ cameraProcess.stdio[0].on('error',function(err){ if(err && rawMonitorConfig.details.loglevel !== 'quiet'){ // s.userLog(e,{type:'STDIN ERROR',msg:err}); } }) }catch(err){ writeToStderr(err.stack) } setTimeout(() => { if(!cameraProcess.stdio[0])return writeToStderr('No Camera Process Found for Snapper'); const captureOne = function(f){ recordingSnapRequest = request({ url: buildMonitorUrl(rawMonitorConfig), method: 'GET', encoding: null, timeout: 15000 },function(err,data){ if(err){ writeToStderr(JSON.stringify(err)) return; } // writeToStderr(data.body.length) cameraProcess.stdio[0].write(data.body) recordingSnapper = setTimeout(function(){ captureOne() },1000 / capture_fps) if(!errorTimeout){ clearTimeout(errorTimeout) errorTimeout = setTimeout(function(){ errorCount = 0; delete(errorTimeout) },3000) } }).on('error', function(err){ ++errorCount clearTimeout(errorTimeout) errorTimeout = null writeToStderr(JSON.stringify(err)) if(rawMonitorConfig.details.loglevel !== 'quiet'){ // s.userLog(e,{ // type: lang['JPEG Error'], // msg: { // msg: lang.JPEGErrorText, // info: err // } // }); switch(err.code){ case'ESOCKETTIMEDOUT': case'ETIMEDOUT': // ++s.group[e.ke].activeMonitors[e.id].errorSocketTimeoutCount // if( // rawMonitorConfig.details.fatal_max !== 0 && // s.group[e.ke].activeMonitors[e.id].errorSocketTimeoutCount > rawMonitorConfig.details.fatal_max // ){ // // s.userLog(e,{type:lang['Fatal Maximum Reached'],msg:{code:'ESOCKETTIMEDOUT',msg:lang.FatalMaximumReachedText}}); // // s.camera('stop',e) // }else{ // // s.userLog(e,{type:lang['Restarting Process'],msg:{code:'ESOCKETTIMEDOUT',msg:lang.FatalMaximumReachedText}}); // // s.camera('restart',e) // } // return; break; } } // if(rawMonitorConfig.details.fatal_max !== 0 && errorCount > rawMonitorConfig.details.fatal_max){ // clearTimeout(recordingSnapper) // process.exit() // } }) } captureOne() },5000) } if( rawMonitorConfig.type === 'dashcam' || rawMonitorConfig.type === 'socket' ){ process.stdin.on('data',(data) => { //confirmed receiving data this way. cameraProcess.stdin.write(data) }) }