mirror of
https://gitlab.com/Shinobi-Systems/ShinobiCE.git
synced 2025-03-09 15:40:15 +00:00
Support Shinobi at https://licenses.shinobi.video/subscribe
This commit is contained in:
parent
ef40f3f231
commit
167603dfb0
118 changed files with 16152 additions and 5441 deletions
255
libs/auth.js
255
libs/auth.js
|
@ -5,109 +5,184 @@ module.exports = function(s,config,lang){
|
|||
s.superUsersApi = {}
|
||||
s.factorAuth = {}
|
||||
s.failedLoginAttempts = {}
|
||||
//auth handler
|
||||
//params = parameters
|
||||
//cb = callback
|
||||
//res = response, only needed for express (http server)
|
||||
//request = request, only needed for express (http server)
|
||||
s.auth = function(params,cb,res,req){
|
||||
//
|
||||
var getUserByUid = function(params,columns,callback){
|
||||
if(!columns)columns = '*'
|
||||
s.sqlQuery(`SELECT ${columns} FROM Users WHERE uid=? AND ke=?`,[params.uid,params.ke],function(err,r){
|
||||
if(!r)r = []
|
||||
var user = r[0]
|
||||
callback(err,user)
|
||||
})
|
||||
}
|
||||
var getUserBySessionKey = function(params,callback){
|
||||
s.sqlQuery('SELECT * FROM Users WHERE auth=? AND ke=?',[params.auth,params.ke],function(err,r){
|
||||
if(!r)r = []
|
||||
var user = r[0]
|
||||
callback(err,user)
|
||||
})
|
||||
}
|
||||
var loginWithUsernameAndPassword = function(params,columns,callback){
|
||||
if(!columns)columns = '*'
|
||||
s.sqlQuery(`SELECT ${columns} FROM Users WHERE mail=? AND (pass=? OR pass=?) LIMIT 1`,[params.username,params.password,s.createHash(params.password)],function(err,r){
|
||||
if(!r)r = []
|
||||
var user = r[0]
|
||||
callback(err,user)
|
||||
})
|
||||
}
|
||||
var getApiKey = function(params,columns,callback){
|
||||
if(!columns)columns = '*'
|
||||
s.sqlQuery(`SELECT ${columns} FROM API WHERE code=? AND ke=?`,[params.auth,params.ke],function(err,r){
|
||||
if(!r)r = []
|
||||
var apiKey = r[0]
|
||||
callback(err,apiKey)
|
||||
})
|
||||
}
|
||||
var loginWithApiKey = function(params,callback){
|
||||
getApiKey(params,'*',function(err,apiKey){
|
||||
var isSessionKey = false
|
||||
if(apiKey){
|
||||
var sessionKey = params.auth
|
||||
createSession(apiKey,{
|
||||
auth: sessionKey,
|
||||
permissions: s.parseJSON(apiKey.details),
|
||||
details: {}
|
||||
})
|
||||
getUserByUid(apiKey,'mail,details',function(err,user){
|
||||
if(user){
|
||||
try{
|
||||
editSession({
|
||||
auth: sessionKey
|
||||
},{
|
||||
mail: user.mail,
|
||||
details: s.parseJSON(user.details),
|
||||
lang: s.getLanguageFile(user.details.lang)
|
||||
})
|
||||
}catch(er){
|
||||
console.log('FAILED TO EDIT',er)
|
||||
}
|
||||
}
|
||||
callback(err,s.api[params.auth])
|
||||
})
|
||||
}else{
|
||||
getUserBySessionKey(params,function(err,user){
|
||||
if(user){
|
||||
isSessionKey = true
|
||||
createSession(apiKey,{
|
||||
details: JSON.parse(user.details),
|
||||
permissions: {}
|
||||
})
|
||||
callback(err,user,isSessionKey)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
var createSession = function(user,additionalData){
|
||||
if(user){
|
||||
var generatedId
|
||||
if(!additionalData)additionalData = {}
|
||||
if(!user.ip)user.ip = '0.0.0.0'
|
||||
if(!user.auth && !user.code){
|
||||
generatedId = s.gid(20)
|
||||
}else{
|
||||
generatedId = user.auth || user.code
|
||||
}
|
||||
user.details = s.parseJSON(user.details)
|
||||
user.permissions = {}
|
||||
s.api[generatedId] = Object.assign(user,additionalData)
|
||||
return generatedId
|
||||
}
|
||||
}
|
||||
var editSession = function(user,additionalData){
|
||||
if(user){
|
||||
if(!additionalData)additionalData = {}
|
||||
Object.keys(additionalData).forEach(function(value,key){
|
||||
s.api[user.auth][key] = value
|
||||
})
|
||||
}
|
||||
}
|
||||
var failHttpAuthentication = function(res,req,message){
|
||||
if(!message)message = lang['Not Authorized']
|
||||
res.end(s.prettyPrint({
|
||||
ok: false,
|
||||
msg: message
|
||||
}))
|
||||
}
|
||||
var resetActiveSessionTimer = function(activeSession){
|
||||
if(activeSession){
|
||||
clearTimeout(activeSession.timeout)
|
||||
activeSession.timeout = setTimeout(function(){
|
||||
delete(activeSession)
|
||||
},1000 * 60 * 5)
|
||||
}
|
||||
}
|
||||
s.auth = function(params,onSuccessComplete,res,req){
|
||||
if(req){
|
||||
//express (http server) use of auth function
|
||||
params.ip=req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||
var failed=function(){
|
||||
if(!req.ret){req.ret={ok:false}}
|
||||
req.ret.msg=lang['Not Authorized'];
|
||||
res.end(s.s(req.ret));
|
||||
params.ip = req.headers['cf-connecting-ip'] || req.headers['x-forwarded-for'] || req.connection.remoteAddress
|
||||
var onFail = function(message){
|
||||
failHttpAuthentication(res,req,message)
|
||||
}
|
||||
}else{
|
||||
//socket.io use of auth function
|
||||
var failed = function(){
|
||||
var onFail = function(){
|
||||
//maybe log
|
||||
}
|
||||
}
|
||||
var clearAfterTime=function(){
|
||||
//remove temp key from memory
|
||||
clearTimeout(s.api[params.auth].timeout)
|
||||
s.api[params.auth].timeout=setTimeout(function(){
|
||||
delete(s.api[params.auth])
|
||||
},1000*60*5)
|
||||
}
|
||||
//check IP address of connecting user
|
||||
var finish=function(user){
|
||||
if(s.api[params.auth].ip.indexOf('0.0.0.0')>-1||s.api[params.auth].ip.indexOf(params.ip)>-1){
|
||||
var onSuccess = function(user){
|
||||
var activeSession = s.api[params.auth]
|
||||
if(
|
||||
activeSession &&
|
||||
(
|
||||
activeSession.ip.indexOf('0.0.0.0') > -1 ||
|
||||
activeSession.ip.indexOf(params.ip) > -1
|
||||
)
|
||||
){
|
||||
if(!user.lang){
|
||||
var details = s.parseJSON(user.details).lang
|
||||
user.lang = s.getDefinitonFile(user.details.lang) || s.copySystemDefaultLanguage()
|
||||
}
|
||||
cb(user);
|
||||
onSuccessComplete(user)
|
||||
}else{
|
||||
failed();
|
||||
onFail()
|
||||
}
|
||||
}
|
||||
//check if auth key is user's temporary session key
|
||||
if(s.group[params.ke]&&s.group[params.ke].users&&s.group[params.ke].users[params.auth]){
|
||||
s.group[params.ke].users[params.auth].permissions={};
|
||||
if(!s.group[params.ke].users[params.auth].lang){
|
||||
s.group[params.ke].users[params.auth].lang = s.copySystemDefaultLanguage()
|
||||
if(s.group[params.ke] && s.group[params.ke].users && s.group[params.ke].users[params.auth]){
|
||||
var activeSession = s.group[params.ke].users[params.auth]
|
||||
activeSession.permissions = {}
|
||||
if(!activeSession.lang){
|
||||
activeSession.lang = s.copySystemDefaultLanguage()
|
||||
}
|
||||
cb(s.group[params.ke].users[params.auth])
|
||||
onSuccessComplete(activeSession)
|
||||
}else{
|
||||
//check if key is already in memory to save query time
|
||||
if(s.api[params.auth]&&s.api[params.auth].details){
|
||||
finish(s.api[params.auth]);
|
||||
if(s.api[params.auth].timeout){
|
||||
clearAfterTime()
|
||||
if(s.api[params.auth] && s.api[params.auth].details){
|
||||
var activeSession = s.api[params.auth]
|
||||
onSuccess(activeSession)
|
||||
if(activeSession.timeout){
|
||||
resetActiveSessionTimer(activeSession)
|
||||
}
|
||||
}else{
|
||||
//no key in memory, query db to see if key exists
|
||||
//check if using username and password in plain text or md5
|
||||
if(params.username&¶ms.username!==''&¶ms.password&¶ms.password!==''){
|
||||
s.sqlQuery('SELECT * FROM Users WHERE mail=? AND (pass=? OR pass=?)',[params.username,params.password,s.createHash(params.password)],function(err,r){
|
||||
if(r&&r[0]){
|
||||
r=r[0];
|
||||
r.ip='0.0.0.0';
|
||||
r.auth = s.gid(20);
|
||||
params.auth = r.auth;
|
||||
r.details=JSON.parse(r.details);
|
||||
r.permissions = {};
|
||||
s.api[r.auth]=r;
|
||||
clearAfterTime();
|
||||
finish(r);
|
||||
if(params.username && params.username !== '' && params.password && params.password !== ''){
|
||||
loginWithUsernameAndPassword(params,'*',function(err,user){
|
||||
if(user){
|
||||
params.auth = user.auth
|
||||
createSession(user)
|
||||
resetActiveSessionTimer(s.api[params.auth])
|
||||
onSuccess(user)
|
||||
}else{
|
||||
failed();
|
||||
onFail()
|
||||
}
|
||||
})
|
||||
}else{
|
||||
//not using plain login
|
||||
s.sqlQuery('SELECT * FROM API WHERE code=? AND ke=?',[params.auth,params.ke],function(err,r){
|
||||
if(r&&r[0]){
|
||||
r=r[0];
|
||||
s.api[params.auth]={ip:r.ip,uid:r.uid,ke:r.ke,permissions:JSON.parse(r.details),details:{}};
|
||||
s.sqlQuery('SELECT mail,details FROM Users WHERE uid=? AND ke=?',[r.uid,r.ke],function(err,rr){
|
||||
if(rr&&rr[0]){
|
||||
rr=rr[0];
|
||||
try{
|
||||
s.api[params.auth].mail=rr.mail
|
||||
s.api[params.auth].details=JSON.parse(rr.details)
|
||||
s.api[params.auth].lang=s.getLanguageFile(s.api[params.auth].details.lang)
|
||||
}catch(er){}
|
||||
}
|
||||
finish(s.api[params.auth]);
|
||||
loginWithApiKey(params,function(err,user,isSessionKey){
|
||||
if(isSessionKey)resetActiveSessionTimer(s.api[params.auth])
|
||||
if(user){
|
||||
createSession(user,{
|
||||
auth: params.auth
|
||||
})
|
||||
onSuccess(s.api[params.auth])
|
||||
}else{
|
||||
s.sqlQuery('SELECT * FROM Users WHERE auth=? AND ke=?',[params.auth,params.ke],function(err,r){
|
||||
if(r&&r[0]){
|
||||
r=r[0];
|
||||
r.ip='0.0.0.0'
|
||||
s.api[params.auth]=r
|
||||
s.api[params.auth].details=JSON.parse(r.details)
|
||||
s.api[params.auth].permissions={}
|
||||
clearAfterTime()
|
||||
finish(r)
|
||||
}else{
|
||||
failed();
|
||||
}
|
||||
})
|
||||
onFail()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -121,8 +196,10 @@ module.exports = function(s,config,lang){
|
|||
var adminUsersSelected = null
|
||||
try{
|
||||
var success = function(){
|
||||
var chosenConfig = config
|
||||
if(req && res){
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
chosenConfig = s.getConfigWithBranding(req.hostname)
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
var ip = req.headers['cf-connecting-ip']||req.headers["CF-Connecting-IP"]||req.headers["'x-forwarded-for"]||req.connection.remoteAddress;
|
||||
var resp = {
|
||||
ok: userFound,
|
||||
|
@ -141,9 +218,9 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
callback({
|
||||
ip : ip,
|
||||
$user:userSelected,
|
||||
users:adminUsersSelected,
|
||||
config:config,
|
||||
$user: userSelected,
|
||||
users: adminUsersSelected,
|
||||
config: chosenConfig,
|
||||
lang:lang
|
||||
})
|
||||
}
|
||||
|
@ -199,4 +276,18 @@ module.exports = function(s,config,lang){
|
|||
return false
|
||||
}
|
||||
}
|
||||
s.basicOrApiAuthentication = function(username,password,callback){
|
||||
var splitUsername = username.split('@')
|
||||
if(splitUsername[1] && splitUsername[1].toLowerCase().indexOf('shinobi') > -1){
|
||||
getApiKey({
|
||||
auth: splitUsername[0],
|
||||
ke: password
|
||||
},'ke,uid',callback)
|
||||
}else{
|
||||
loginWithUsernameAndPassword({
|
||||
username: username,
|
||||
password: password
|
||||
},'ke,uid',callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
var moment = require('moment');
|
||||
var crypto = require('crypto');
|
||||
var exec = require('child_process').exec;
|
||||
var fs = require('fs')
|
||||
var moment = require('moment')
|
||||
var crypto = require('crypto')
|
||||
var exec = require('child_process').exec
|
||||
var spawn = require('child_process').spawn;
|
||||
var events = require('events');
|
||||
var http = require('http');
|
||||
var https = require('https');
|
||||
var events = require('events')
|
||||
var http = require('http')
|
||||
var https = require('https')
|
||||
const async = require("async")
|
||||
module.exports = function(s,config){
|
||||
//kill any ffmpeg running
|
||||
s.ffmpegKill=function(){
|
||||
|
@ -75,7 +77,12 @@ module.exports = function(s,config){
|
|||
break;
|
||||
}
|
||||
//load camera controller vars
|
||||
s.nameToTime=function(x){x=x.split('.')[0].split('T'),x[1]=x[1].replace(/-/g,':');x=x.join(' ');return x;}
|
||||
s.nameToTime=function(x){
|
||||
x = x.split('.')[0].split('T')
|
||||
if(x[1])x[1] = x[1].replace(/-/g,':')
|
||||
x = x.join(' ')
|
||||
return x
|
||||
}
|
||||
s.ratio=function(width,height,ratio){ratio = width / height;return ( Math.abs( ratio - 4 / 3 ) < Math.abs( ratio - 16 / 9 ) ) ? '4:3' : '16:9';}
|
||||
s.randomNumber=function(x){
|
||||
if(!x){x=10};
|
||||
|
@ -206,7 +213,7 @@ module.exports = function(s,config){
|
|||
}
|
||||
return url
|
||||
}
|
||||
s.file=function(x,e){
|
||||
s.file = function(x,e,callback){
|
||||
if(!e){e={}};
|
||||
switch(x){
|
||||
case'size':
|
||||
|
@ -214,19 +221,25 @@ module.exports = function(s,config){
|
|||
break;
|
||||
case'delete':
|
||||
if(!e){return false;}
|
||||
return exec('rm -f '+e,{detached: true});
|
||||
return exec('rm -f '+e,{detached: true},function(err){
|
||||
if(callback)callback(err)
|
||||
})
|
||||
break;
|
||||
case'deleteFolder':
|
||||
if(!e){return false;}
|
||||
return exec('rm -rf '+e,{detached: true});
|
||||
exec('rm -rf '+e,{detached: true},function(err){
|
||||
if(callback)callback(err)
|
||||
})
|
||||
break;
|
||||
case'deleteFiles':
|
||||
if(!e.age_type){e.age_type='min'};if(!e.age){e.age='1'};
|
||||
exec('find '+e.path+' -type f -c'+e.age_type+' +'+e.age+' -exec rm -f {} +',{detached: true});
|
||||
exec('find '+e.path+' -type f -c'+e.age_type+' +'+e.age+' -exec rm -f {} +',{detached: true},function(err){
|
||||
if(callback)callback(err)
|
||||
})
|
||||
break;
|
||||
}
|
||||
}
|
||||
s.createTimeout = function(timeoutVar,timeoutLength,defaultLength,multiplier,callback){
|
||||
s.createTimeout = function(timeoutVar,parentVar,timeoutLength,defaultLength,multiplier,callback){
|
||||
var theTimeout
|
||||
if(!multiplier)multiplier = 1000 * 60
|
||||
if(!timeoutLength || timeoutLength === ''){
|
||||
|
@ -234,12 +247,43 @@ module.exports = function(s,config){
|
|||
}else{
|
||||
theTimeout = parseFloat(timeoutLength) * multiplier
|
||||
}
|
||||
clearTimeout(timeoutVar)
|
||||
timeoutVar = setTimeout(function(){
|
||||
clearTimeout(timeoutVar)
|
||||
delete(timeoutVar)
|
||||
clearTimeout(parentVar[timeoutVar])
|
||||
parentVar[timeoutVar] = setTimeout(function(){
|
||||
clearTimeout(parentVar[timeoutVar])
|
||||
delete(parentVar[timeoutVar])
|
||||
if(callback)callback()
|
||||
},theTimeout)
|
||||
return parentVar[timeoutVar]
|
||||
}
|
||||
s.handleFolderError = function(err){
|
||||
if(err){
|
||||
switch(err.code){
|
||||
case'EEXIST':
|
||||
break;
|
||||
default:
|
||||
console.log(err)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
s.isCorrectFilenameSyntax = function(string){
|
||||
return RegExp('[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]T[0-9][0-9]-[0-9][0-9]-[0-9][0-9]').test(string)
|
||||
}
|
||||
var readFile = async.queue(function(filename, callback) {
|
||||
fs.readFile(filename,"utf-8",callback)
|
||||
}, 4);
|
||||
s.readFile = function(filename, callback){
|
||||
return readFile.push(filename, callback)
|
||||
}
|
||||
var fileStats = async.queue(function(filename, callback) {
|
||||
fs.stat(filename,callback)
|
||||
}, 4);
|
||||
s.fileStats = function(filename, callback){
|
||||
return fileStats.push(filename, callback)
|
||||
}
|
||||
s.kilobyteToMegabyte = function(kb,places){
|
||||
if(!places)places = 2
|
||||
return (kb/1000000).toFixed(places)
|
||||
}
|
||||
Object.defineProperty(Array.prototype, 'chunk', {
|
||||
value: function(chunkSize){
|
||||
|
|
20
libs/branding.js
Normal file
20
libs/branding.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
module.exports = function(s,config,lang,app,io){
|
||||
if(config.showPoweredByShinobi === undefined){config.showPoweredByShinobi=true}
|
||||
if(config.poweredByShinobi === undefined){config.poweredByShinobi='Powered by Shinobi.Systems'}
|
||||
if(config.poweredByShinobiClass === undefined){config.poweredByShinobiClass='margin:15px 0 0 0;text-align:center;color:#777;font-family: sans-serif;text-transform: uppercase;letter-spacing: 3;font-size: 8pt;'}
|
||||
if(config.webPageTitle === undefined){config.webPageTitle='Shinobi'}
|
||||
if(config.showLoginCardHeader === undefined){config.showLoginCardHeader=true}
|
||||
if(config.webFavicon === undefined){config.webFavicon='libs/img/icon/favicon.ico'}
|
||||
if(config.logoLocation76x76 === undefined){config.logoLocation76x76='libs/img/icon/apple-touch-icon-76x76.png'}
|
||||
if(config.logoLocation76x76Link === undefined){config.logoLocation76x76Link='https://shinobi.video'}
|
||||
if(config.logoLocation76x76Style === undefined){config.logoLocation76x76Style='border-radius:50%'}
|
||||
if(config.showLoginSelector === undefined){config.showLoginSelector=true}
|
||||
|
||||
s.getConfigWithBranding = function(domain){
|
||||
var configCopy = Object.assign({},config)
|
||||
if(config.brandingConfig && config.brandingConfig[domain]){
|
||||
return Object.assign(configCopy,config.brandingConfig[domain])
|
||||
}
|
||||
return config
|
||||
}
|
||||
}
|
|
@ -13,7 +13,10 @@ module.exports = function(s,config,lang,app,io){
|
|||
console.log(lang.Shinobi+' - CHILD NODE PORT : '+config.childNodes.port);
|
||||
});
|
||||
s.debugLog('childNodeWebsocket.attach(childNodeServer)')
|
||||
childNodeWebsocket.attach(childNodeServer);
|
||||
childNodeWebsocket.attach(childNodeServer,{
|
||||
path:'/socket.io',
|
||||
transports: ['websocket']
|
||||
});
|
||||
//send data to child node function (experimental)
|
||||
s.cx = function(z,y,x){
|
||||
if(!z.mid && !z.d){
|
||||
|
@ -27,10 +30,12 @@ module.exports = function(s,config,lang,app,io){
|
|||
//child Node Websocket
|
||||
childNodeWebsocket.on('connection', function (cn) {
|
||||
//functions for dispersing work to child servers;
|
||||
var ipAddress
|
||||
cn.on('c',function(d){
|
||||
if(config.childNodes.key.indexOf(d.socketKey) > -1){
|
||||
if(!cn.shinobi_child&&d.f=='init'){
|
||||
cn.ip = cn.request.connection.remoteAddress.replace('::ffff:','')+':'+d.port
|
||||
ipAddress = cn.request.connection.remoteAddress.replace('::ffff:','')+':'+d.port
|
||||
cn.ip = ipAddress
|
||||
cn.shinobi_child = 1
|
||||
tx = function(z){
|
||||
cn.emit('c',z)
|
||||
|
@ -38,8 +43,10 @@ module.exports = function(s,config,lang,app,io){
|
|||
if(!s.childNodes[cn.ip]){
|
||||
s.childNodes[cn.ip] = {}
|
||||
};
|
||||
s.childNodes[cn.ip].dead = false
|
||||
s.childNodes[cn.ip].cnid = cn.id
|
||||
s.childNodes[cn.ip].cpu = 0
|
||||
s.childNodes[cn.ip].ip = ipAddress
|
||||
s.childNodes[cn.ip].activeCameras = {}
|
||||
d.availableHWAccels.forEach(function(accel){
|
||||
if(config.availableHWAccels.indexOf(accel) === -1)config.availableHWAccels.push(accel)
|
||||
|
@ -52,13 +59,16 @@ module.exports = function(s,config,lang,app,io){
|
|||
}else{
|
||||
switch(d.f){
|
||||
case'cpu':
|
||||
s.childNodes[cn.ip].cpu = d.cpu;
|
||||
s.childNodes[ipAddress].cpu = d.cpu;
|
||||
break;
|
||||
case'sql':
|
||||
s.sqlQuery(d.query,d.values,function(err,rows){
|
||||
cn.emit('c',{f:'sqlCallback',rows:rows,err:err,callbackId:d.callbackId});
|
||||
});
|
||||
break;
|
||||
case'clearCameraFromActiveList':
|
||||
if(s.childNodes[ipAddress])delete(s.childNodes[ipAddress].activeCameras[d.ke + d.id])
|
||||
break;
|
||||
case'camera':
|
||||
s.camera(d.mode,d.data)
|
||||
break;
|
||||
|
@ -69,24 +79,54 @@ module.exports = function(s,config,lang,app,io){
|
|||
if(!d.mon || !d.data)return console.log('LOG DROPPED',d.mon,d.data);
|
||||
s.userLog(d.mon,d.data)
|
||||
break;
|
||||
case'created_file_chunk':
|
||||
if(!s.group[d.ke].mon[d.mid].childNodeStreamWriters[d.filename]){
|
||||
d.dir = s.getVideoDirectory(s.group[d.ke].mon_conf[d.mid])
|
||||
s.group[d.ke].mon[d.mid].childNodeStreamWriters[d.filename] = fs.createWriteStream(d.dir+d.filename)
|
||||
case'open_timelapse_file_transfer':
|
||||
var location = s.getTimelapseFrameDirectory(d.d) + `${d.currentDate}/`
|
||||
if(!fs.existsSync(location)){
|
||||
fs.mkdirSync(location)
|
||||
}
|
||||
s.group[d.ke].mon[d.mid].childNodeStreamWriters[d.filename].write(d.chunk)
|
||||
break;
|
||||
case'created_file':
|
||||
if(!s.group[d.ke].mon[d.mid].childNodeStreamWriters[d.filename]){
|
||||
case'created_timelapse_file_chunk':
|
||||
if(!s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename]){
|
||||
var dir = s.getTimelapseFrameDirectory(d.d) + `${d.currentDate}/`
|
||||
s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename] = fs.createWriteStream(dir+d.filename)
|
||||
}
|
||||
s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename].write(d.chunk)
|
||||
break;
|
||||
case'created_timelapse_file':
|
||||
if(!s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename]){
|
||||
return console.log('FILE NOT EXIST')
|
||||
}
|
||||
s.group[d.ke].mon[d.mid].childNodeStreamWriters[d.filename].end();
|
||||
s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename].end()
|
||||
tx({
|
||||
f: 'deleteTimelapseFrame',
|
||||
file: d.filename,
|
||||
currentDate: d.currentDate,
|
||||
d: d.d, //monitor config
|
||||
ke: d.ke,
|
||||
mid: d.mid
|
||||
})
|
||||
s.insertTimelapseFrameDatabaseRow({
|
||||
ke: d.ke
|
||||
},d.queryInfo)
|
||||
break;
|
||||
case'created_file_chunk':
|
||||
if(!s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename]){
|
||||
d.dir = s.getVideoDirectory(s.group[d.ke].rawMonitorConfigurations[d.mid])
|
||||
s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename] = fs.createWriteStream(d.dir+d.filename)
|
||||
}
|
||||
s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename].write(d.chunk)
|
||||
break;
|
||||
case'created_file':
|
||||
if(!s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename]){
|
||||
return console.log('FILE NOT EXIST')
|
||||
}
|
||||
s.group[d.ke].activeMonitors[d.mid].childNodeStreamWriters[d.filename].end();
|
||||
tx({
|
||||
f:'delete',
|
||||
file:d.filename,
|
||||
ke:d.ke,
|
||||
mid:d.mid
|
||||
});
|
||||
})
|
||||
s.txWithSubPermissions({
|
||||
f:'video_build_success',
|
||||
hrefNoAuth:'/videos/'+d.ke+'/'+d.mid+'/'+d.filename,
|
||||
|
@ -115,28 +155,39 @@ module.exports = function(s,config,lang,app,io){
|
|||
s.purgeDiskForGroup(d)
|
||||
//send new diskUsage values
|
||||
s.setDiskUsedForGroup(d,insert.filesizeMB)
|
||||
clearTimeout(s.group[d.ke].mon[d.mid].recordingChecker)
|
||||
clearTimeout(s.group[d.ke].mon[d.mid].streamChecker)
|
||||
clearTimeout(s.group[d.ke].activeMonitors[d.mid].recordingChecker)
|
||||
clearTimeout(s.group[d.ke].activeMonitors[d.mid].streamChecker)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
cn.on('disconnect',function(){
|
||||
console.log('childNodeWebsocket.disconnect')
|
||||
|
||||
if(s.childNodes[cn.ip]){
|
||||
var activeCameraKeys = Object.keys(s.childNodes[cn.ip].activeCameras)
|
||||
activeCameraKeys.forEach(function(key){
|
||||
var monitor = s.childNodes[cn.ip].activeCameras[key]
|
||||
s.camera('stop',s.cleanMonitorObject(monitor))
|
||||
delete(s.group[monitor.ke].mon[monitor.mid].childNode)
|
||||
delete(s.group[monitor.ke].mon[monitor.mid].childNodeId)
|
||||
setTimeout(function(){
|
||||
s.camera(monitor.mode,s.cleanMonitorObject(monitor))
|
||||
},1300)
|
||||
})
|
||||
delete(s.childNodes[cn.ip]);
|
||||
console.log('childNodeWebsocket.disconnect',ipAddress)
|
||||
if(s.childNodes[ipAddress]){
|
||||
var monitors = Object.values(s.childNodes[ipAddress].activeCameras)
|
||||
if(monitors && monitors[0]){
|
||||
var loadCompleted = 0
|
||||
var loadMonitor = function(monitor){
|
||||
setTimeout(function(){
|
||||
var mode = monitor.mode + ''
|
||||
var cleanMonitor = s.cleanMonitorObject(monitor)
|
||||
s.camera('stop',Object.assign(cleanMonitor,{}))
|
||||
delete(s.group[monitor.ke].activeMonitors[monitor.mid].childNode)
|
||||
delete(s.group[monitor.ke].activeMonitors[monitor.mid].childNodeId)
|
||||
setTimeout(function(){
|
||||
s.camera(mode,cleanMonitor)
|
||||
++loadCompleted
|
||||
if(monitors[loadCompleted]){
|
||||
loadMonitor(monitors[loadCompleted])
|
||||
}
|
||||
},1000)
|
||||
},2000)
|
||||
}
|
||||
loadMonitor(monitors[loadCompleted])
|
||||
}
|
||||
s.childNodes[ipAddress].activeCameras = {}
|
||||
s.childNodes[ipAddress].dead = true
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -144,7 +195,9 @@ module.exports = function(s,config,lang,app,io){
|
|||
//setup Child for childNodes
|
||||
if(config.childNodes.enabled === true && config.childNodes.mode === 'child' && config.childNodes.host){
|
||||
s.connected = false;
|
||||
childIO = require('socket.io-client')('ws://'+config.childNodes.host);
|
||||
childIO = require('socket.io-client')('ws://'+config.childNodes.host,{
|
||||
transports: ['websocket']
|
||||
});
|
||||
s.cx = function(x){x.socketKey = config.childNodes.key;childIO.emit('c',x)}
|
||||
s.tx = function(x,y){s.cx({f:'s.tx',data:x,to:y})}
|
||||
s.userLog = function(x,y){s.cx({f:'s.userLog',mon:x,data:y})}
|
||||
|
@ -162,9 +215,9 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
setInterval(function(){
|
||||
s.cpuUsage(function(cpu){
|
||||
io.emit('c',{f:'cpu',cpu:parseFloat(cpu)});
|
||||
s.cx({f:'cpu',cpu:parseFloat(cpu)})
|
||||
})
|
||||
},2000);
|
||||
},2000)
|
||||
childIO.on('connect', function(d){
|
||||
console.log('CHILD CONNECTION SUCCESS')
|
||||
s.cx({
|
||||
|
@ -188,17 +241,22 @@ module.exports = function(s,config,lang,app,io){
|
|||
break;
|
||||
case'kill':
|
||||
s.initiateMonitorObject(d.d);
|
||||
s.cameraDestroy(s.group[d.d.ke].mon[d.d.id].spawn,d.d)
|
||||
s.cameraDestroy(s.group[d.d.ke].activeMonitors[d.d.id].spawn,d.d)
|
||||
var childNodeIp = s.group[d.d.ke].activeMonitors[d.d.id]
|
||||
break;
|
||||
case'sync':
|
||||
s.initiateMonitorObject(d.sync);
|
||||
Object.keys(d.sync).forEach(function(v){
|
||||
s.group[d.sync.ke].mon[d.sync.mid][v]=d.sync[v];
|
||||
s.group[d.sync.ke].activeMonitors[d.sync.mid][v]=d.sync[v];
|
||||
});
|
||||
break;
|
||||
case'delete'://delete video
|
||||
s.file('delete',s.dir.videos+d.ke+'/'+d.mid+'/'+d.file)
|
||||
break;
|
||||
case'deleteTimelapseFrame'://delete video
|
||||
var filePath = s.getTimelapseFrameDirectory(d.d) + `${d.currentDate}/` + d.file
|
||||
s.file('delete',filePath)
|
||||
break;
|
||||
case'insertCompleted'://close video
|
||||
s.insertCompletedVideo(d.d,d.k)
|
||||
break;
|
||||
|
@ -212,6 +270,15 @@ module.exports = function(s,config,lang,app,io){
|
|||
})
|
||||
childIO.on('disconnect',function(d){
|
||||
s.connected = false;
|
||||
var groupKeys = Object.keys(s.group)
|
||||
groupKeys.forEach(function(groupKey){
|
||||
var activeMonitorKeys = Object.keys(s.group[groupKey].activeMonitors)
|
||||
activeMonitorKeys.forEach(function(monitorKey){
|
||||
var activeMonitor = s.group[groupKey].activeMonitors[monitorKey]
|
||||
if(activeMonitor && activeMonitor.spawn && activeMonitor.spawn.close)activeMonitor.spawn.close()
|
||||
if(activeMonitor && activeMonitor.spawn && activeMonitor.spawn.kill)activeMonitor.spawn.kill()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ module.exports = function(s){
|
|||
}
|
||||
var config = require(s.location.config);
|
||||
if(!config.productType){
|
||||
config.productType='CE'
|
||||
config.productType = 'CE'
|
||||
}
|
||||
//config defaults
|
||||
if(config.cpuUsageMarker === undefined){config.cpuUsageMarker='%Cpu'}
|
||||
if(config.customCpuCommand === undefined){config.customCpuCommand=null}
|
||||
if(config.autoDropCache === undefined){config.autoDropCache=true}
|
||||
if(config.autoDropCache === undefined){config.autoDropCache=false}
|
||||
if(config.doSnapshot === undefined){config.doSnapshot=true}
|
||||
if(config.restart === undefined){config.restart={}}
|
||||
if(config.systemLog === undefined){config.systemLog=true}
|
||||
|
@ -27,7 +27,8 @@ module.exports = function(s){
|
|||
if(config.cron.deleteOverMaxOffset === undefined)config.cron.deleteOverMaxOffset=0.9;
|
||||
if(config.cron.deleteLogs === undefined)config.cron.deleteLogs=true;
|
||||
if(config.cron.deleteEvents === undefined)config.cron.deleteEvents=true;
|
||||
if(config.cron.deleteFileBins === undefined)config.cron.deleteFileBins=true;
|
||||
if(config.cron.deleteFileBinsOverMax === undefined)config.cron.deleteFileBins=true;
|
||||
if(config.deleteFileBins === undefined)config.deleteFileBinsOverMax=true;
|
||||
if(config.cron.interval === undefined)config.cron.interval=1;
|
||||
if(config.databaseType === undefined){config.databaseType='mysql'}
|
||||
if(config.pluginKeys === undefined)config.pluginKeys={};
|
||||
|
@ -37,7 +38,7 @@ module.exports = function(s){
|
|||
if(config.pipeAddition === undefined){config.pipeAddition=10}else{config.pipeAddition=parseInt(config.pipeAddition)}
|
||||
if(config.hideCloudSaveUrls === undefined){config.hideCloudSaveUrls = true}
|
||||
if(config.insertOrphans === undefined){config.insertOrphans = true}
|
||||
if(config.orphanedVideoCheckMax === undefined){config.orphanedVideoCheckMax = 20}
|
||||
if(config.orphanedVideoCheckMax === undefined){config.orphanedVideoCheckMax = 2}
|
||||
if(config.detectorMergePamRegionTriggers === undefined){config.detectorMergePamRegionTriggers = false}
|
||||
//Child Nodes
|
||||
if(config.childNodes === undefined)config.childNodes = {};
|
||||
|
|
|
@ -1,6 +1,28 @@
|
|||
var fs = require('fs')
|
||||
var express = require('express')
|
||||
module.exports = function(s,config,lang,app,io){
|
||||
function mergeDeep(...objects) {
|
||||
const isObject = obj => obj && typeof obj === 'object';
|
||||
|
||||
return objects.reduce((prev, obj) => {
|
||||
Object.keys(obj).forEach(key => {
|
||||
const pVal = prev[key];
|
||||
const oVal = obj[key];
|
||||
|
||||
if (Array.isArray(pVal) && Array.isArray(oVal)) {
|
||||
prev[key] = pVal.concat(...oVal);
|
||||
}
|
||||
else if (isObject(pVal) && isObject(oVal)) {
|
||||
prev[key] = mergeDeep(pVal, oVal);
|
||||
}
|
||||
else {
|
||||
prev[key] = oVal;
|
||||
}
|
||||
});
|
||||
|
||||
return prev;
|
||||
}, {});
|
||||
}
|
||||
s.customAutoLoadModules = {}
|
||||
s.customAutoLoadTree = {
|
||||
pages: [],
|
||||
|
@ -14,7 +36,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
superLibsJs: [],
|
||||
superLibsCss: []
|
||||
}
|
||||
var folderPath = __dirname + '/customAutoLoad'
|
||||
var folderPath = s.mainDirectory + '/libs/customAutoLoad'
|
||||
var search = function(searchFor,searchIn){return searchIn.indexOf(searchFor) > -1}
|
||||
fs.readdir(folderPath,function(err,folderContents){
|
||||
if(!err && folderContents){
|
||||
|
@ -117,6 +139,24 @@ module.exports = function(s,config,lang,app,io){
|
|||
})
|
||||
})
|
||||
break;
|
||||
case'definitions':
|
||||
var definitionsFolder = s.checkCorrectPathEnding(customModulePath) + 'definitions/'
|
||||
fs.readdir(definitionsFolder,function(err,files){
|
||||
if(err)return console.log(err);
|
||||
files.forEach(function(filename){
|
||||
var fileData = require(definitionsFolder + filename)
|
||||
var rule = filename.replace('.json','').replace('.js','')
|
||||
if(config.language === rule){
|
||||
s.definitions = mergeDeep(s.definitions,fileData)
|
||||
}
|
||||
if(s.loadedDefinitons[rule]){
|
||||
s.loadedDefinitons[rule] = mergeDeep(s.loadedDefinitons[rule],fileData)
|
||||
}else{
|
||||
s.loadedDefinitons[rule] = mergeDeep(s.copySystemDefaultDefinitions(),fileData)
|
||||
}
|
||||
})
|
||||
})
|
||||
break;
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
44
libs/definitions.js
Normal file
44
libs/definitions.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
var fs = require('fs')
|
||||
var express = require('express')
|
||||
module.exports = function(s,config,lang,app,io){
|
||||
s.location.definitions = s.mainDirectory+'/definitions'
|
||||
try{
|
||||
var definitions = require(s.location.definitions+'/'+config.language+'.js')(s,config,lang)
|
||||
}catch(er){
|
||||
console.error(er)
|
||||
console.log('There was an error loading your definition file.')
|
||||
try{
|
||||
var definitions = require(s.location.definitions+'/en_CA.js')(s,config,lang)
|
||||
}catch(er){
|
||||
console.error(er)
|
||||
console.log('There was an error loading your definition file.')
|
||||
var definitions = require(s.location.definitions+'/en_CA.json');
|
||||
}
|
||||
}
|
||||
//load defintions dynamically
|
||||
s.definitions = definitions
|
||||
s.copySystemDefaultDefinitions = function(){
|
||||
//en_CA
|
||||
return Object.assign(s.definitions,{})
|
||||
}
|
||||
s.loadedDefinitons={}
|
||||
s.loadedDefinitons[config.language] = s.copySystemDefaultDefinitions()
|
||||
s.getDefinitonFile = function(rule){
|
||||
if(rule && rule !== ''){
|
||||
var file = s.loadedDefinitons[rule]
|
||||
if(!file){
|
||||
try{
|
||||
s.loadedDefinitons[rule] = require(s.location.definitions+'/'+rule+'.js')(s,config,lang)
|
||||
s.loadedDefinitons[rule] = Object.assign(s.copySystemDefaultDefinitions(),s.loadedDefinitons[rule])
|
||||
file = s.loadedDefinitons[rule]
|
||||
}catch(err){
|
||||
file = s.copySystemDefaultDefinitions()
|
||||
}
|
||||
}
|
||||
}else{
|
||||
file = s.copySystemDefaultDefinitions()
|
||||
}
|
||||
return file
|
||||
}
|
||||
return definitions
|
||||
}
|
|
@ -13,9 +13,9 @@ module.exports = function(s,config){
|
|||
globalSensitivity,
|
||||
globalColorThreshold,
|
||||
fullFrame = false
|
||||
if(s.group[e.ke].mon_conf[e.id].details.detector_scale_x===''||s.group[e.ke].mon_conf[e.id].details.detector_scale_y===''){
|
||||
width = s.group[e.ke].mon_conf[e.id].details.detector_scale_x;
|
||||
height = s.group[e.ke].mon_conf[e.id].details.detector_scale_y;
|
||||
if(s.group[e.ke].rawMonitorConfigurations[e.id].details.detector_scale_x===''||s.group[e.ke].rawMonitorConfigurations[e.id].details.detector_scale_y===''){
|
||||
width = s.group[e.ke].rawMonitorConfigurations[e.id].details.detector_scale_x;
|
||||
height = s.group[e.ke].rawMonitorConfigurations[e.id].details.detector_scale_y;
|
||||
}else{
|
||||
width = e.width
|
||||
height = e.height
|
||||
|
@ -35,9 +35,9 @@ module.exports = function(s,config){
|
|||
|
||||
var regionJson
|
||||
try{
|
||||
regionJson = JSON.parse(s.group[e.ke].mon_conf[e.id].details.cords)
|
||||
regionJson = JSON.parse(s.group[e.ke].rawMonitorConfigurations[e.id].details.cords)
|
||||
}catch(err){
|
||||
regionJson = s.group[e.ke].mon_conf[e.id].details.cords
|
||||
regionJson = s.group[e.ke].rawMonitorConfigurations[e.id].details.cords
|
||||
}
|
||||
|
||||
if(Object.keys(regionJson).length === 0 || e.details.detector_frame === '1'){
|
||||
|
@ -64,8 +64,8 @@ module.exports = function(s,config){
|
|||
if(e.details.detector_show_matrix==='1'){
|
||||
pamDiffOptions.response = 'bounds'
|
||||
}
|
||||
s.group[e.ke].mon[e.id].pamDiff = new PamDiff(pamDiffOptions);
|
||||
s.group[e.ke].mon[e.id].p2p = new P2P()
|
||||
s.group[e.ke].activeMonitors[e.id].pamDiff = new PamDiff(pamDiffOptions);
|
||||
s.group[e.ke].activeMonitors[e.id].p2p = new P2P()
|
||||
var regionArray = Object.values(regionJson)
|
||||
if(config.detectorMergePamRegionTriggers === true){
|
||||
// merge pam triggers for performance boost
|
||||
|
@ -116,12 +116,12 @@ module.exports = function(s,config){
|
|||
}
|
||||
}
|
||||
if(e.details.detector_noise_filter==='1'){
|
||||
if(!s.group[e.ke].mon[e.id].noiseFilterArray)s.group[e.ke].mon[e.id].noiseFilterArray = {}
|
||||
var noiseFilterArray = s.group[e.ke].mon[e.id].noiseFilterArray
|
||||
if(!s.group[e.ke].activeMonitors[e.id].noiseFilterArray)s.group[e.ke].activeMonitors[e.id].noiseFilterArray = {}
|
||||
var noiseFilterArray = s.group[e.ke].activeMonitors[e.id].noiseFilterArray
|
||||
Object.keys(regions.notForPam).forEach(function(name){
|
||||
if(!noiseFilterArray[name])noiseFilterArray[name]=[];
|
||||
})
|
||||
s.group[e.ke].mon[e.id].pamDiff.on('diff', (data) => {
|
||||
s.group[e.ke].activeMonitors[e.id].pamDiff.on('diff', (data) => {
|
||||
var filteredCount = 0
|
||||
var filteredCountSuccess = 0
|
||||
data.trigger.forEach(function(trigger){
|
||||
|
@ -135,7 +135,7 @@ module.exports = function(s,config){
|
|||
})
|
||||
})
|
||||
}else{
|
||||
s.group[e.ke].mon[e.id].pamDiff.on('diff', (data) => {
|
||||
s.group[e.ke].activeMonitors[e.id].pamDiff.on('diff', (data) => {
|
||||
buildTriggerEvent(s.mergePamTriggers(data))
|
||||
})
|
||||
}
|
||||
|
@ -170,12 +170,12 @@ module.exports = function(s,config){
|
|||
})
|
||||
}
|
||||
if(e.details.detector_noise_filter==='1'){
|
||||
if(!s.group[e.ke].mon[e.id].noiseFilterArray)s.group[e.ke].mon[e.id].noiseFilterArray = {}
|
||||
var noiseFilterArray = s.group[e.ke].mon[e.id].noiseFilterArray
|
||||
if(!s.group[e.ke].activeMonitors[e.id].noiseFilterArray)s.group[e.ke].activeMonitors[e.id].noiseFilterArray = {}
|
||||
var noiseFilterArray = s.group[e.ke].activeMonitors[e.id].noiseFilterArray
|
||||
Object.keys(regions.notForPam).forEach(function(name){
|
||||
if(!noiseFilterArray[name])noiseFilterArray[name]=[];
|
||||
})
|
||||
s.group[e.ke].mon[e.id].pamDiff.on('diff', (data) => {
|
||||
s.group[e.ke].activeMonitors[e.id].pamDiff.on('diff', (data) => {
|
||||
data.trigger.forEach(function(trigger){
|
||||
s.filterTheNoise(e,noiseFilterArray,regions,trigger,function(){
|
||||
s.createMatrixFromPamTrigger(trigger)
|
||||
|
@ -184,7 +184,7 @@ module.exports = function(s,config){
|
|||
})
|
||||
})
|
||||
}else{
|
||||
s.group[e.ke].mon[e.id].pamDiff.on('diff', (data) => {
|
||||
s.group[e.ke].activeMonitors[e.id].pamDiff.on('diff', (data) => {
|
||||
data.trigger.forEach(function(trigger){
|
||||
s.createMatrixFromPamTrigger(trigger)
|
||||
buildTriggerEvent(trigger)
|
||||
|
@ -210,7 +210,14 @@ module.exports = function(s,config){
|
|||
if(!region)return false;
|
||||
region.polygon = [];
|
||||
region.points.forEach(function(points){
|
||||
region.polygon.push({x:parseFloat(points[0]),y:parseFloat(points[1])})
|
||||
var x = parseFloat(points[0]);
|
||||
var y = parseFloat(points[1]);
|
||||
if(x < 0)x = 0;
|
||||
if(y < 0)y = 0;
|
||||
region.polygon.push({
|
||||
x: x,
|
||||
y: y
|
||||
})
|
||||
})
|
||||
if(region.sensitivity===''){
|
||||
region.sensitivity = globalSensitivity
|
||||
|
|
|
@ -1,35 +1,8 @@
|
|||
var fs = require('fs')
|
||||
var execSync = require('child_process').execSync
|
||||
module.exports = function(s,config,lang,app,io){
|
||||
if(config.dropInEventServer === true){
|
||||
if(config.dropInEventForceSaveEvent === undefined)config.dropInEventForceSaveEvent = true
|
||||
if(config.dropInEventDeleteFileAfterTrigger === undefined)config.dropInEventDeleteFileAfterTrigger = true
|
||||
var authenticateUser = function(username,password,callback){
|
||||
var splitUsername = username.split('@')
|
||||
if(splitUsername[1] !== 'Shinobi' && splitUsername[1] !== 'shinobi'){
|
||||
s.sqlQuery('SELECT ke,uid FROM Users WHERE mail=? AND (pass=? OR pass=?)',[
|
||||
username,
|
||||
password,
|
||||
s.createHash(password)
|
||||
],function(err,r){
|
||||
var user
|
||||
if(r && r[0]){
|
||||
user = r[0]
|
||||
}
|
||||
callback(err,user)
|
||||
})
|
||||
}else{
|
||||
s.sqlQuery('SELECT ke,uid FROM API WHERE code=? AND ke=?',[
|
||||
splitUsername[0], //code
|
||||
password //ke
|
||||
],function(err,r){
|
||||
var apiKey
|
||||
if(r && r[0]){
|
||||
apiKey = r[0]
|
||||
}
|
||||
callback(err,apiKey)
|
||||
})
|
||||
}
|
||||
}
|
||||
var beforeMonitorsLoadedOnStartup = function(){
|
||||
if(!config.dropInEventsDir){
|
||||
config.dropInEventsDir = s.dir.streams + 'dropInEvents/'
|
||||
|
@ -50,74 +23,131 @@ module.exports = function(s,config,lang,app,io){
|
|||
var onMonitorStop = function(monitorConfig){
|
||||
var ke = monitorConfig.ke
|
||||
var mid = monitorConfig.mid
|
||||
if(s.group[monitorConfig.ke].mon[monitorConfig.mid].dropInEventWatcher){
|
||||
s.group[monitorConfig.ke].mon[monitorConfig.mid].dropInEventWatcher.close()
|
||||
delete(s.group[monitorConfig.ke].mon[monitorConfig.mid].dropInEventWatcher)
|
||||
if(s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].dropInEventWatcher){
|
||||
s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].dropInEventWatcher.close()
|
||||
delete(s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].dropInEventWatcher)
|
||||
var monitorEventDropDir = getDropInEventDir(monitorConfig)
|
||||
s.file('deleteFolder',monitorEventDropDir + '*')
|
||||
}
|
||||
var monitorEventDropDir = getDropInEventDir(monitorConfig)
|
||||
if(fs.existsSync(monitorEventDropDir))execSync('rm -rf ' + monitorEventDropDir)
|
||||
}
|
||||
var createDropInEventDirectory = function(e,callback){
|
||||
var directory = s.dir.dropInEvents + e.ke + '/'
|
||||
fs.mkdir(directory,function(err){
|
||||
s.handleFolderError(err)
|
||||
directory = s.dir.dropInEvents + e.ke + '/' + (e.id || e.mid) + '/'
|
||||
fs.mkdir(directory,function(err){
|
||||
s.handleFolderError(err)
|
||||
callback(err,directory)
|
||||
})
|
||||
})
|
||||
}
|
||||
var onMonitorInit = function(monitorConfig){
|
||||
onMonitorStop(monitorConfig)
|
||||
var ke = monitorConfig.ke
|
||||
var mid = monitorConfig.mid
|
||||
var monitorEventDropDir = getDropInEventDir(monitorConfig)
|
||||
var groupEventDropDir = s.dir.dropInEvents + ke
|
||||
if(!fs.existsSync(groupEventDropDir)){
|
||||
fs.mkdirSync(groupEventDropDir)
|
||||
}
|
||||
var monitorEventDropDir = groupEventDropDir + '/' + mid + '/'
|
||||
if(!fs.existsSync(monitorEventDropDir)){
|
||||
fs.mkdirSync(monitorEventDropDir)
|
||||
}
|
||||
var fileQueue = {}
|
||||
s.group[monitorConfig.ke].mon[monitorConfig.mid].dropInEventFileQueue = fileQueue
|
||||
var eventTrigger = function(eventType,filename){
|
||||
var filePath = monitorEventDropDir + filename
|
||||
if(filename.indexOf('.jpg') > -1 || filename.indexOf('.jpeg') > -1){
|
||||
var snapPath = s.dir.streams + ke + '/' + mid + '/s.jpg'
|
||||
fs.unlink(snapPath,function(err){
|
||||
fs.createReadStream(filePath).pipe(fs.createWriteStream(snapPath))
|
||||
s.triggerEvent({
|
||||
id: mid,
|
||||
ke: ke,
|
||||
details: {
|
||||
confidence: 100,
|
||||
name: filename,
|
||||
plug: "dropInEvent",
|
||||
reason: "dropInEvent"
|
||||
createDropInEventDirectory(monitorConfig,function(err,monitorEventDropDir){
|
||||
var monitorEventDropDir = getDropInEventDir(monitorConfig)
|
||||
var fileQueue = {}
|
||||
s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].dropInEventFileQueue = fileQueue
|
||||
var search = function(searchIn,searchFor){
|
||||
return searchIn.indexOf(searchFor) > -1
|
||||
}
|
||||
var processFile = function(filename){
|
||||
var filePath = monitorEventDropDir + filename
|
||||
if(search(filename,'.jpg') || search(filename,'.jpeg')){
|
||||
var snapPath = s.dir.streams + ke + '/' + mid + '/s.jpg'
|
||||
fs.unlink(snapPath,function(err){
|
||||
fs.createReadStream(filePath).pipe(fs.createWriteStream(snapPath))
|
||||
s.triggerEvent({
|
||||
id: mid,
|
||||
ke: ke,
|
||||
details: {
|
||||
confidence: 100,
|
||||
name: filename,
|
||||
plug: "dropInEvent",
|
||||
reason: "ftpServer"
|
||||
},
|
||||
},config.dropInEventForceSaveEvent)
|
||||
})
|
||||
}else{
|
||||
var reason = "ftpServer"
|
||||
if(search(filename,'.mp4')){
|
||||
fs.stat(filePath,function(err,stats){
|
||||
var startTime = stats.ctime
|
||||
var endTime = stats.mtime
|
||||
var shinobiFilename = s.formattedTime(startTime) + '.mp4'
|
||||
var recordingPath = s.getVideoDirectory(monitorConfig) + shinobiFilename
|
||||
var writeStream = fs.createWriteStream(recordingPath)
|
||||
fs.createReadStream(filePath).pipe(writeStream)
|
||||
writeStream.on('finish', () => {
|
||||
s.insertCompletedVideo(s.group[monitorConfig.ke].rawMonitorConfigurations[monitorConfig.mid],{
|
||||
file : shinobiFilename
|
||||
},function(){
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
var completeAction = function(){
|
||||
s.triggerEvent({
|
||||
id: mid,
|
||||
ke: ke,
|
||||
details: {
|
||||
confidence: 100,
|
||||
name: filename,
|
||||
plug: "dropInEvent",
|
||||
reason: reason
|
||||
}
|
||||
},config.dropInEventForceSaveEvent)
|
||||
}
|
||||
if(search(filename,'.txt')){
|
||||
fs.readFile(filePath,{encoding: 'utf-8'},function(err,data){
|
||||
if(data){
|
||||
reason = data.split('\n')[0] || filename
|
||||
}else if(filename){
|
||||
reason = filename
|
||||
}
|
||||
completeAction()
|
||||
})
|
||||
}else{
|
||||
completeAction()
|
||||
}
|
||||
|
||||
}
|
||||
if(config.dropInEventDeleteFileAfterTrigger){
|
||||
setTimeout(function(){
|
||||
fs.unlink(filePath,function(err){
|
||||
|
||||
})
|
||||
},1000 * 60 * 5)
|
||||
}
|
||||
}
|
||||
var eventTrigger = function(eventType,filename,stats){
|
||||
if(stats.isDirectory()){
|
||||
fs.readdir(monitorEventDropDir + filename,function(err,files){
|
||||
if(files){
|
||||
files.forEach(function(filename){
|
||||
processFile(filename)
|
||||
})
|
||||
}else if(err){
|
||||
console.log(err)
|
||||
}
|
||||
})
|
||||
})
|
||||
}else{
|
||||
s.triggerEvent({
|
||||
id: mid,
|
||||
ke: ke,
|
||||
details: {
|
||||
confidence: 100,
|
||||
name: filename,
|
||||
plug: "dropInEvent",
|
||||
reason: "ftpServer"
|
||||
}else{
|
||||
processFile(filename)
|
||||
}
|
||||
}
|
||||
var directoryWatch = fs.watch(monitorEventDropDir,function(eventType,filename){
|
||||
fs.stat(monitorEventDropDir + filename,function(err,stats){
|
||||
if(!err){
|
||||
clearTimeout(fileQueue[filename])
|
||||
fileQueue[filename] = setTimeout(function(){
|
||||
eventTrigger(eventType,filename,stats)
|
||||
},1750)
|
||||
}
|
||||
})
|
||||
}
|
||||
if(config.dropInEventDeleteFileAfterTrigger){
|
||||
setTimeout(function(){
|
||||
fs.unlink(filePath,function(err){
|
||||
|
||||
})
|
||||
},1000 * 60 * 5)
|
||||
}
|
||||
}
|
||||
var directoryWatch = fs.watch(monitorEventDropDir,function(eventType,filename){
|
||||
if(fs.existsSync(monitorEventDropDir + filename)){
|
||||
clearTimeout(fileQueue[filename])
|
||||
fileQueue[filename] = setTimeout(function(){
|
||||
eventTrigger(eventType,filename)
|
||||
},1200)
|
||||
}
|
||||
})
|
||||
s.group[monitorConfig.ke].activeMonitors[monitorConfig.mid].dropInEventWatcher = directoryWatch
|
||||
})
|
||||
s.group[monitorConfig.ke].mon[monitorConfig.mid].dropInEventWatcher = directoryWatch
|
||||
}
|
||||
// FTP Server
|
||||
if(config.ftpServer === true){
|
||||
|
@ -127,13 +157,12 @@ module.exports = function(s,config,lang,app,io){
|
|||
const FtpSrv = require('ftp-srv')
|
||||
const ftpServer = new FtpSrv({
|
||||
url: config.ftpServerUrl,
|
||||
// log:{trace:function(){},error:function(){},child:function(){},info:function(){},warn:function(){}
|
||||
})
|
||||
|
||||
ftpServer.on('login', (data, resolve, reject) => {
|
||||
var username = data.username
|
||||
var password = data.password
|
||||
authenticateUser(username,password,function(err,user){
|
||||
s.basicOrApiAuthentication(username,password,function(err,user){
|
||||
if(user){
|
||||
resolve({root: s.dir.dropInEvents + user.ke})
|
||||
}else{
|
||||
|
@ -141,7 +170,9 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
})
|
||||
})
|
||||
|
||||
ftpServer.on('client-error', ({connection, context, error}) => {
|
||||
console.log('error')
|
||||
})
|
||||
ftpServer.listen().then(() => {
|
||||
s.systemLog(`FTP Server running on port ${config.ftpServerPort}...`)
|
||||
}).catch(function(err){
|
||||
|
@ -156,13 +187,15 @@ module.exports = function(s,config,lang,app,io){
|
|||
// SMTP Server
|
||||
// allow starting SMTP server without dropInEventServer
|
||||
if(config.smtpServer === true){
|
||||
if(config.smtpServerHideStartTls === undefined)config.smtpServerHideStartTls = null
|
||||
var SMTPServer = require("smtp-server").SMTPServer;
|
||||
if(!config.smtpServerPort && (config.smtpServerSsl && config.smtpServerSsl.enabled !== false || config.ssl)){config.smtpServerPort = 465}else if(!config.smtpServerPort){config.smtpServerPort = 25}
|
||||
var smtpOptions = {
|
||||
hideSTARTTLS: config.smtpServerHideStartTls,
|
||||
onAuth(auth, session, callback) {
|
||||
var username = auth.username
|
||||
var password = auth.password
|
||||
authenticateUser(username,password,function(err,user){
|
||||
s.basicOrApiAuthentication(username,password,function(err,user){
|
||||
if(user){
|
||||
callback(null, {user: user.ke})
|
||||
}else{
|
||||
|
@ -174,21 +207,61 @@ module.exports = function(s,config,lang,app,io){
|
|||
var split = address.address.split('@')
|
||||
var monitorId = split[0]
|
||||
var ke = session.user
|
||||
if(s.group[ke].mon_conf[monitorId] && s.group[ke].mon[monitorId].isStarted === true){
|
||||
s.triggerEvent({
|
||||
id: monitorId,
|
||||
ke: ke,
|
||||
details: {
|
||||
confidence: 100,
|
||||
name: address.address,
|
||||
plug: "dropInEvent",
|
||||
reason: "smtpServer"
|
||||
}
|
||||
})
|
||||
if(s.group[ke].rawMonitorConfigurations[monitorId] && s.group[ke].activeMonitors[monitorId].isStarted === true){
|
||||
session.monitorId = monitorId
|
||||
}else{
|
||||
return callback(new Error(lang['No Monitor Exists with this ID.']))
|
||||
}
|
||||
callback()
|
||||
},
|
||||
onData(stream, session, callback) {
|
||||
if(session.monitorId){
|
||||
var ke = session.user
|
||||
var monitorId = session.monitorId
|
||||
var reasonTag = 'smtpServer'
|
||||
var text = ''
|
||||
stream.on('data',function(data){
|
||||
text += data.toString()
|
||||
}) // print message to console
|
||||
stream.on("end", function(){
|
||||
var contentPart = text.split('--PartBoundary12345678')
|
||||
contentPart.forEach(function(part){
|
||||
var parsed = {}
|
||||
var lines = part.split(/\r?\n/)
|
||||
lines.forEach(function(line,n){
|
||||
var pieces = line.split(':')
|
||||
if(pieces[1]){
|
||||
var nextLine = lines[n + 1]
|
||||
var keyName = pieces[0].trim().toLowerCase()
|
||||
pieces.shift()
|
||||
var parsedValue = pieces.join(':')
|
||||
parsed[keyName] = parsedValue
|
||||
}
|
||||
})
|
||||
if(parsed['content-type'] && parsed['content-type'].indexOf('image/jpeg') > -1){
|
||||
// console.log(lines)
|
||||
}
|
||||
if(parsed['alarm event']){
|
||||
reasonTag = parsed['alarm event']
|
||||
}else if(parsed.subject){
|
||||
reasonTag = parsed.subject
|
||||
}
|
||||
})
|
||||
s.triggerEvent({
|
||||
id: monitorId,
|
||||
ke: ke,
|
||||
details: {
|
||||
confidence: 100,
|
||||
name: 'smtpServer',
|
||||
plug: "dropInEvent",
|
||||
reason: reasonTag
|
||||
}
|
||||
},config.dropInEventForceSaveEvent)
|
||||
callback()
|
||||
})
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
if(config.smtpServerSsl && config.smtpServerSsl.enabled !== false || config.ssl && config.ssl.cert && config.ssl.key){
|
||||
|
|
111
libs/events.js
111
libs/events.js
|
@ -41,7 +41,7 @@ module.exports = function(s,config,lang){
|
|||
extender(x,d)
|
||||
})
|
||||
}
|
||||
s.triggerEvent = function(d){
|
||||
s.triggerEvent = function(d,forceSave){
|
||||
var filter = {
|
||||
halt : false,
|
||||
addToMotionCounter : true,
|
||||
|
@ -56,11 +56,11 @@ module.exports = function(s,config,lang){
|
|||
extender(d,filter)
|
||||
})
|
||||
var detailString = JSON.stringify(d.details);
|
||||
if(!s.group[d.ke]||!s.group[d.ke].mon[d.id]){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].activeMonitors[d.id]){
|
||||
return s.systemLog(lang['No Monitor Found, Ignoring Request'])
|
||||
}
|
||||
d.mon=s.group[d.ke].mon_conf[d.id];
|
||||
var currentConfig = s.group[d.ke].mon[d.id].details
|
||||
d.mon=s.group[d.ke].rawMonitorConfigurations[d.id];
|
||||
var currentConfig = s.group[d.ke].activeMonitors[d.id].details
|
||||
var hasMatrices = (d.details.matrices && d.details.matrices.length > 0)
|
||||
//read filters
|
||||
if(
|
||||
|
@ -185,15 +185,16 @@ module.exports = function(s,config,lang){
|
|||
d.details.matrices = reviewedMatrix
|
||||
}
|
||||
}
|
||||
var eventTime = new Date()
|
||||
//motion counter
|
||||
if(filter.addToMotionCounter && filter.record){
|
||||
if(!s.group[d.ke].mon[d.id].detector_motion_count){
|
||||
s.group[d.ke].mon[d.id].detector_motion_count=0
|
||||
if(!s.group[d.ke].activeMonitors[d.id].detector_motion_count){
|
||||
s.group[d.ke].activeMonitors[d.id].detector_motion_count=0
|
||||
}
|
||||
s.group[d.ke].mon[d.id].detector_motion_count+=1
|
||||
s.group[d.ke].activeMonitors[d.id].detector_motion_count+=1
|
||||
}
|
||||
if(filter.useLock){
|
||||
if(s.group[d.ke].mon[d.id].motion_lock){
|
||||
if(s.group[d.ke].activeMonitors[d.id].motion_lock){
|
||||
return
|
||||
}
|
||||
var detector_lock_timeout
|
||||
|
@ -201,10 +202,10 @@ module.exports = function(s,config,lang){
|
|||
detector_lock_timeout = 2000
|
||||
}
|
||||
detector_lock_timeout = parseFloat(currentConfig.detector_lock_timeout);
|
||||
if(!s.group[d.ke].mon[d.id].detector_lock_timeout){
|
||||
s.group[d.ke].mon[d.id].detector_lock_timeout=setTimeout(function(){
|
||||
clearTimeout(s.group[d.ke].mon[d.id].detector_lock_timeout)
|
||||
delete(s.group[d.ke].mon[d.id].detector_lock_timeout)
|
||||
if(!s.group[d.ke].activeMonitors[d.id].detector_lock_timeout){
|
||||
s.group[d.ke].activeMonitors[d.id].detector_lock_timeout=setTimeout(function(){
|
||||
clearTimeout(s.group[d.ke].activeMonitors[d.id].detector_lock_timeout)
|
||||
delete(s.group[d.ke].activeMonitors[d.id].detector_lock_timeout)
|
||||
},detector_lock_timeout)
|
||||
}else{
|
||||
return
|
||||
|
@ -212,7 +213,7 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
// check if object should be in region
|
||||
if(hasMatrices && currentConfig.detector_obj_region === '1'){
|
||||
var regions = s.group[d.ke].mon[d.id].parsedObjects.cords
|
||||
var regions = s.group[d.ke].activeMonitors[d.id].parsedObjects.cords
|
||||
var isMatrixInRegions = s.isAtleastOneMatrixInRegion(regions,d.details.matrices)
|
||||
if(isMatrixInRegions){
|
||||
s.debugLog('Matrix in region!')
|
||||
|
@ -229,14 +230,14 @@ module.exports = function(s,config,lang){
|
|||
if(d.doObjectDetection === true){
|
||||
s.ocvTx({
|
||||
f : 'frame',
|
||||
mon : s.group[d.ke].mon_conf[d.id].details,
|
||||
mon : s.group[d.ke].rawMonitorConfigurations[d.id].details,
|
||||
ke : d.ke,
|
||||
id : d.id,
|
||||
time : s.formattedTime(),
|
||||
frame : s.group[d.ke].mon[d.id].lastJpegDetectorFrame
|
||||
frame : s.group[d.ke].activeMonitors[d.id].lastJpegDetectorFrame
|
||||
})
|
||||
}else{
|
||||
if(currentConfig.detector_multi_trigger === '1'){
|
||||
if(currentConfig.det_multi_trig === '1'){
|
||||
s.getCamerasForMultiTrigger(d.mon).forEach(function(monitor){
|
||||
if(monitor.mid !== d.id){
|
||||
s.triggerEvent({
|
||||
|
@ -253,8 +254,8 @@ module.exports = function(s,config,lang){
|
|||
})
|
||||
}
|
||||
//save this detection result in SQL, only coords. not image.
|
||||
if(filter.save && currentConfig.detector_save === '1'){
|
||||
s.sqlQuery('INSERT INTO Events (ke,mid,details,time) VALUES (?,?,?,?)',[d.ke,d.id,detailString,new Date()])
|
||||
if(forceSave || (filter.save && currentConfig.detector_save === '1')){
|
||||
s.sqlQuery('INSERT INTO Events (ke,mid,details,time) VALUES (?,?,?,?)',[d.ke,d.id,detailString,eventTime])
|
||||
}
|
||||
if(currentConfig.detector_notrigger === '1'){
|
||||
var detector_notrigger_timeout
|
||||
|
@ -262,9 +263,9 @@ module.exports = function(s,config,lang){
|
|||
detector_notrigger_timeout = 10
|
||||
}
|
||||
detector_notrigger_timeout = parseFloat(currentConfig.detector_notrigger_timeout)*1000*60;
|
||||
s.group[d.ke].mon[d.id].detector_notrigger_timeout = detector_notrigger_timeout;
|
||||
clearInterval(s.group[d.ke].mon[d.id].detector_notrigger_timeout)
|
||||
s.group[d.ke].mon[d.id].detector_notrigger_timeout = setInterval(s.group[d.ke].mon[d.id].detector_notrigger_timeout_function,detector_notrigger_timeout)
|
||||
s.group[d.ke].activeMonitors[d.id].detector_notrigger_timeout = detector_notrigger_timeout;
|
||||
clearInterval(s.group[d.ke].activeMonitors[d.id].detector_notrigger_timeout)
|
||||
s.group[d.ke].activeMonitors[d.id].detector_notrigger_timeout = setInterval(s.group[d.ke].activeMonitors[d.id].detector_notrigger_timeout_function,detector_notrigger_timeout)
|
||||
}
|
||||
var detector_timeout
|
||||
if(!currentConfig.detector_timeout||currentConfig.detector_timeout===''){
|
||||
|
@ -273,7 +274,7 @@ module.exports = function(s,config,lang){
|
|||
detector_timeout = parseFloat(currentConfig.detector_timeout)
|
||||
}
|
||||
if(filter.record && d.mon.mode=='start'&¤tConfig.detector_trigger==='1'&¤tConfig.detector_record_method==='sip'){
|
||||
s.createEventBasedRecording(d)
|
||||
s.createEventBasedRecording(d,moment(eventTime).subtract(5,'seconds').format('YYYY-MM-DDTHH-mm-ss'))
|
||||
}else if(filter.record && d.mon.mode!=='stop'&¤tConfig.detector_trigger=='1'&¤tConfig.detector_record_method==='hot'){
|
||||
if(!d.auth){
|
||||
d.auth=s.gid();
|
||||
|
@ -314,26 +315,32 @@ module.exports = function(s,config,lang){
|
|||
|
||||
if(filter.webhook && currentConfig.detector_webhook === '1'){
|
||||
var detector_webhook_url = addEventDetailsToString(d,currentConfig.detector_webhook_url)
|
||||
request({url:detector_webhook_url,method:'GET',encoding:null},function(err,data){
|
||||
var webhookMethod = currentConfig.detector_webhook_method
|
||||
if(!webhookMethod || webhookMethod === '')webhookMethod = 'GET'
|
||||
request(detector_webhook_url,{method: webhookMethod,encoding:null},function(err,data){
|
||||
if(err){
|
||||
s.userLog(d,{type:lang["Event Webhook Error"],msg:{error:err,data:data}})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if(filter.command && currentConfig.detector_command_enable === '1' && !s.group[d.ke].mon[d.id].detector_command){
|
||||
s.createTimeout(s.group[d.ke].mon[d.id].detector_command,currentConfig.detector_command_timeout,10)
|
||||
if(filter.command && currentConfig.detector_command_enable === '1' && !s.group[d.ke].activeMonitors[d.id].detector_command){
|
||||
s.group[d.ke].activeMonitors[d.id].detector_command = s.createTimeout('detector_command',s.group[d.ke].activeMonitors[d.id],currentConfig.detector_command_timeout,10)
|
||||
var detector_command = addEventDetailsToString(d,currentConfig.detector_command)
|
||||
exec(detector_command,{detached: true})
|
||||
if(detector_command === '')return
|
||||
exec(detector_command,{detached: true},function(err){
|
||||
if(err)s.debugLog(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
//show client machines the event
|
||||
d.cx={f:'detector_trigger',id:d.id,ke:d.ke,details:d.details,doObjectDetection:d.doObjectDetection};
|
||||
s.tx(d.cx,'DETECTOR_'+d.ke+d.id);
|
||||
}
|
||||
s.createEventBasedRecording = function(d){
|
||||
d.mon = s.group[d.ke].mon_conf[d.id]
|
||||
var currentConfig = s.group[d.ke].mon[d.id].details
|
||||
s.createEventBasedRecording = function(d,fileTime){
|
||||
if(!fileTime)fileTime = s.formattedTime()
|
||||
d.mon = s.group[d.ke].rawMonitorConfigurations[d.id]
|
||||
var currentConfig = s.group[d.ke].activeMonitors[d.id].details
|
||||
if(currentConfig.detector !== '1'){
|
||||
return
|
||||
}
|
||||
|
@ -343,29 +350,29 @@ module.exports = function(s,config,lang){
|
|||
}else{
|
||||
detector_timeout = parseFloat(currentConfig.detector_timeout)
|
||||
}
|
||||
if(currentConfig.watchdog_reset === '1' || !s.group[d.ke].mon[d.id].eventBasedRecording.timeout){
|
||||
clearTimeout(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
|
||||
s.group[d.ke].mon[d.id].eventBasedRecording.timeout = setTimeout(function(){
|
||||
s.group[d.ke].mon[d.id].eventBasedRecording.allowEnd = true
|
||||
s.group[d.ke].mon[d.id].eventBasedRecording.process.stdin.setEncoding('utf8')
|
||||
s.group[d.ke].mon[d.id].eventBasedRecording.process.stdin.write('q')
|
||||
delete(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
|
||||
if(currentConfig.watchdog_reset === '1' || !s.group[d.ke].activeMonitors[d.id].eventBasedRecording.timeout){
|
||||
clearTimeout(s.group[d.ke].activeMonitors[d.id].eventBasedRecording.timeout)
|
||||
s.group[d.ke].activeMonitors[d.id].eventBasedRecording.timeout = setTimeout(function(){
|
||||
s.group[d.ke].activeMonitors[d.id].eventBasedRecording.allowEnd = true
|
||||
s.group[d.ke].activeMonitors[d.id].eventBasedRecording.process.stdin.setEncoding('utf8')
|
||||
s.group[d.ke].activeMonitors[d.id].eventBasedRecording.process.stdin.write('q')
|
||||
delete(s.group[d.ke].activeMonitors[d.id].eventBasedRecording.timeout)
|
||||
},detector_timeout * 1000 * 60)
|
||||
}
|
||||
if(!s.group[d.ke].mon[d.id].eventBasedRecording.process){
|
||||
s.group[d.ke].mon[d.id].eventBasedRecording.allowEnd = false;
|
||||
if(!s.group[d.ke].activeMonitors[d.id].eventBasedRecording.process){
|
||||
s.group[d.ke].activeMonitors[d.id].eventBasedRecording.allowEnd = false;
|
||||
var runRecord = function(){
|
||||
var filename = s.formattedTime()+'.mp4'
|
||||
var filename = fileTime+'.mp4'
|
||||
s.userLog(d,{type:lang["Traditional Recording"],msg:lang["Started"]})
|
||||
//-t 00:'+s.timeObject(new Date(detector_timeout * 1000 * 60)).format('mm:ss')+'
|
||||
s.group[d.ke].mon[d.id].eventBasedRecording.process = spawn(config.ffmpegDir,s.splitForFFPMEG(('-loglevel warning -analyzeduration 1000000 -probesize 1000000 -re -i "'+s.dir.streams+'/'+d.ke+'/'+d.id+'/detectorStream.m3u8" -c:v copy -strftime 1 "'+s.getVideoDirectory(d.mon) + filename + '"')))
|
||||
s.group[d.ke].activeMonitors[d.id].eventBasedRecording.process = spawn(config.ffmpegDir,s.splitForFFPMEG(('-loglevel warning -analyzeduration 1000000 -probesize 1000000 -re -i "'+s.dir.streams+'/'+d.ke+'/'+d.id+'/detectorStream.m3u8" -c:v copy -strftime 1 "'+s.getVideoDirectory(d.mon) + filename + '"')))
|
||||
var ffmpegError='';
|
||||
var error
|
||||
s.group[d.ke].mon[d.id].eventBasedRecording.process.stderr.on('data',function(data){
|
||||
s.group[d.ke].activeMonitors[d.id].eventBasedRecording.process.stderr.on('data',function(data){
|
||||
s.userLog(d,{type:lang["Traditional Recording"],msg:data.toString()})
|
||||
})
|
||||
s.group[d.ke].mon[d.id].eventBasedRecording.process.on('close',function(){
|
||||
if(!s.group[d.ke].mon[d.id].eventBasedRecording.allowEnd){
|
||||
s.group[d.ke].activeMonitors[d.id].eventBasedRecording.process.on('close',function(){
|
||||
if(!s.group[d.ke].activeMonitors[d.id].eventBasedRecording.allowEnd){
|
||||
s.userLog(d,{type:lang["Traditional Recording"],msg:lang["Detector Recording Process Exited Prematurely. Restarting."]})
|
||||
runRecord()
|
||||
return
|
||||
|
@ -375,22 +382,22 @@ module.exports = function(s,config,lang){
|
|||
})
|
||||
s.userLog(d,{type:lang["Traditional Recording"],msg:lang["Detector Recording Complete"]})
|
||||
s.userLog(d,{type:lang["Traditional Recording"],msg:lang["Clear Recorder Process"]})
|
||||
delete(s.group[d.ke].mon[d.id].eventBasedRecording.process)
|
||||
clearTimeout(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
|
||||
delete(s.group[d.ke].mon[d.id].eventBasedRecording.timeout)
|
||||
clearTimeout(s.group[d.ke].mon[d.id].recordingChecker)
|
||||
delete(s.group[d.ke].activeMonitors[d.id].eventBasedRecording.process)
|
||||
clearTimeout(s.group[d.ke].activeMonitors[d.id].eventBasedRecording.timeout)
|
||||
delete(s.group[d.ke].activeMonitors[d.id].eventBasedRecording.timeout)
|
||||
clearTimeout(s.group[d.ke].activeMonitors[d.id].recordingChecker)
|
||||
})
|
||||
}
|
||||
runRecord()
|
||||
}
|
||||
}
|
||||
s.closeEventBasedRecording = function(e){
|
||||
if(s.group[e.ke].mon[e.id].eventBasedRecording.process){
|
||||
clearTimeout(s.group[e.ke].mon[e.id].eventBasedRecording.timeout)
|
||||
s.group[e.ke].mon[e.id].eventBasedRecording.allowEnd = true;
|
||||
s.group[e.ke].mon[e.id].eventBasedRecording.process.kill('SIGTERM');
|
||||
if(s.group[e.ke].activeMonitors[e.id].eventBasedRecording.process){
|
||||
clearTimeout(s.group[e.ke].activeMonitors[e.id].eventBasedRecording.timeout)
|
||||
s.group[e.ke].activeMonitors[e.id].eventBasedRecording.allowEnd = true;
|
||||
s.group[e.ke].activeMonitors[e.id].eventBasedRecording.process.kill('SIGTERM');
|
||||
}
|
||||
// var stackedProcesses = s.group[e.ke].mon[e.id].eventBasedRecording.stackable
|
||||
// var stackedProcesses = s.group[e.ke].activeMonitors[e.id].eventBasedRecording.stackable
|
||||
// Object.keys(stackedProcesses).forEach(function(key){
|
||||
// var item = stackedProcesses[key]
|
||||
// clearTimeout(item.timeout)
|
||||
|
|
|
@ -143,4 +143,28 @@ module.exports = function(s,config){
|
|||
s.onWebSocketDisconnectionExtensions.push(callback)
|
||||
}
|
||||
//
|
||||
s.onGetCpuUsageExtensions = []
|
||||
s.onGetCpuUsage = function(callback){
|
||||
s.onGetCpuUsageExtensions.push(callback)
|
||||
}
|
||||
//
|
||||
s.onGetRamUsageExtensions = []
|
||||
s.onGetRamUsage = function(callback){
|
||||
s.onGetRamUsageExtensions.push(callback)
|
||||
}
|
||||
//
|
||||
/////// VIDEOS ////////
|
||||
s.insertCompletedVideoExtensions = []
|
||||
s.insertCompletedVideoExtender = function(callback){
|
||||
s.insertCompletedVideoExtensions.push(callback)
|
||||
}
|
||||
s.onBeforeInsertCompletedVideoExtensions = []
|
||||
s.onBeforeInsertCompletedVideo = function(callback){
|
||||
s.onBeforeInsertCompletedVideoExtensions.push(callback)
|
||||
}
|
||||
/////// TIMELAPSE ////////
|
||||
s.onInsertTimelapseFrameExtensions = []
|
||||
s.onInsertTimelapseFrame = function(callback){
|
||||
s.onInsertTimelapseFrameExtensions.push(callback)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
var fs = require('fs');
|
||||
var spawn = require('child_process').spawn;
|
||||
var execSync = require('child_process').execSync;
|
||||
module.exports = function(s,config,onFinish){
|
||||
module.exports = function(s,config,lang,onFinish){
|
||||
if(config.ffmpegBinary)config.ffmpegDir = config.ffmpegBinary
|
||||
var ffmpeg = {}
|
||||
var downloadingFfmpeg = false;
|
||||
//check local ffmpeg
|
||||
|
@ -98,6 +99,27 @@ module.exports = function(s,config,onFinish){
|
|||
config.availableHWAccels = availableHWAccels
|
||||
config.availableHWAccels = ['auto'].concat(config.availableHWAccels)
|
||||
console.log('Available Hardware Acceleration Methods : ',availableHWAccels.join(', '))
|
||||
var methods = {
|
||||
auto: {label:lang['Auto'],value:'auto'},
|
||||
drm: {label:lang['drm'],value:'drm'},
|
||||
cuvid: {label:lang['cuvid'],value:'cuvid'},
|
||||
vaapi: {label:lang['vaapi'],value:'vaapi'},
|
||||
qsv: {label:lang['qsv'],value:'qsv'},
|
||||
vdpau: {label:lang['vdpau'],value:'vdpau'},
|
||||
dxva2: {label:lang['dxva2'],value:'dxva2'},
|
||||
vdpau: {label:lang['vdpau'],value:'vdpau'},
|
||||
videotoolbox: {label:lang['videotoolbox'],value:'videotoolbox'}
|
||||
}
|
||||
s.listOfHwAccels = []
|
||||
config.availableHWAccels.forEach(function(availibleMethod){
|
||||
if(methods[availibleMethod]){
|
||||
var method = methods[availibleMethod]
|
||||
s.listOfHwAccels.push({
|
||||
name: method.label,
|
||||
value: method.value,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
callback()
|
||||
}
|
||||
|
@ -471,8 +493,7 @@ module.exports = function(s,config,onFinish){
|
|||
if(e.details.stream_timestamp_box_color&&e.details.stream_timestamp_box_color!==''){x.stream_timestamp_box_color=e.details.stream_timestamp_box_color}else{x.stream_timestamp_box_color='0x00000000@1'}
|
||||
//text size
|
||||
if(e.details.stream_timestamp_font_size&&e.details.stream_timestamp_font_size!==''){x.stream_timestamp_font_size=e.details.stream_timestamp_font_size}else{x.stream_timestamp_font_size='10'}
|
||||
|
||||
x.stream_video_filters.push('drawtext=fontfile='+x.stream_timestamp_font+':text=\'%{localtime}\':x='+x.stream_timestamp_x+':y='+x.stream_timestamp_y+':fontcolor='+x.stream_timestamp_color+':box=1:boxcolor='+x.stream_timestamp_box_color+':fontsize='+x.stream_timestamp_font_size);
|
||||
x.stream_video_filters.push('drawtext="fontfile='+x.stream_timestamp_font+':text=\'%{localtime}\':x='+x.stream_timestamp_x+':y='+x.stream_timestamp_y+':fontcolor='+x.stream_timestamp_color+':box=1:boxcolor='+x.stream_timestamp_box_color+':fontsize='+x.stream_timestamp_font_size + '"');
|
||||
}
|
||||
//stream - watermark for -vf
|
||||
if(e.details.stream_watermark&&e.details.stream_watermark=="1"&&e.details.stream_watermark_location&&e.details.stream_watermark_location!==''){
|
||||
|
@ -540,6 +561,7 @@ module.exports = function(s,config,onFinish){
|
|||
//add input feed map
|
||||
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.stream)
|
||||
}
|
||||
if(e.details.stream_fps&&e.details.stream_fps!==''){x.stream_fps=' -r '+e.details.stream_fps}else{x.stream_fps = ''}
|
||||
if(x.stream_fps && (e.details.stream_vcodec !== 'copy' || e.details.stream_type === 'mjpeg' || e.details.stream_type === 'b64')){
|
||||
x.cust_stream += x.stream_fps
|
||||
}
|
||||
|
@ -638,8 +660,8 @@ module.exports = function(s,config,onFinish){
|
|||
x.record_video_filters = []
|
||||
x.record_string = ''
|
||||
//record - resolution
|
||||
if(e.width!==''&&e.height!==''&&!isNaN(e.width)&&!isNaN(e.height)){
|
||||
x.record_dimensions=' -s '+e.width+'x'+e.height
|
||||
if(e.record_scale_x!==''&&e.record_scale_y!==''&&e.record_scale_x!=='0'&&e.record_scale_y!=='0'&&!isNaN(e.record_scale_x)&&!isNaN(e.record_scale_y)){
|
||||
x.record_dimensions=' -s '+e.record_scale_x+'x'+e.record_scale_y
|
||||
}else{
|
||||
x.record_dimensions=''
|
||||
}
|
||||
|
@ -647,12 +669,13 @@ module.exports = function(s,config,onFinish){
|
|||
x.dimensions = e.details.stream_scale_x+'x'+e.details.stream_scale_y;
|
||||
}
|
||||
//record - segmenting
|
||||
x.segment=' -f segment -segment_format_options movflags=faststart+frag_keyframe+empty_moov -segment_atclocktime 1 -reset_timestamps 1 -strftime 1 -segment_list pipe:2 -segment_time '+(60*e.cutoff)+' "'+e.dir+'%Y-%m-%dT%H-%M-%S.'+e.ext+'"';
|
||||
x.segment = ' -f segment -segment_atclocktime 1 -reset_timestamps 1 -strftime 1 -segment_list pipe:2 -segment_time '+(60*e.cutoff)+' "'+e.dir+'%Y-%m-%dT%H-%M-%S.'+e.ext+'"';
|
||||
//record - set defaults for extension, video quality
|
||||
switch(e.ext){
|
||||
case'mp4':
|
||||
x.vcodec='libx264';x.acodec='aac';
|
||||
if(e.details.crf&&e.details.crf!==''){x.vcodec+=' -crf '+e.details.crf}
|
||||
x.record_video_filters.push(`-segment_format_options movflags=faststart+frag_keyframe+empty_moov`)
|
||||
break;
|
||||
case'webm':
|
||||
x.acodec='libvorbis',x.vcodec='libvpx';
|
||||
|
@ -680,8 +703,6 @@ module.exports = function(s,config,onFinish){
|
|||
if(x.vcodec.indexOf('none')>-1){x.vcodec=''}else{x.vcodec=' -vcodec '+x.vcodec}
|
||||
//record - frames per second (fps)
|
||||
if(e.fps&&e.fps!==''&&e.details.vcodec!=='copy'){x.record_fps=' -r '+e.fps}else{x.record_fps=''}
|
||||
//stream - frames per second (fps)
|
||||
if(e.details.stream_fps&&e.details.stream_fps!==''){x.stream_fps=' -r '+e.details.stream_fps}else{x.stream_fps = ''}
|
||||
//record - timestamp options for -vf
|
||||
if(e.details.timestamp&&e.details.timestamp=="1"&&e.details.vcodec!=='copy'){
|
||||
//font
|
||||
|
@ -792,9 +813,11 @@ module.exports = function(s,config,onFinish){
|
|||
if(sendFramesGlobally)x.pipe += ' -an -c:v pam -pix_fmt gray -f image2pipe pipe:3'
|
||||
if(e.details.detector_use_detect_object === '1'){
|
||||
//for object detection
|
||||
x.detector_fps_object = '2'
|
||||
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.detector)
|
||||
if(e.details.detector_scale_x_object&&e.details.detector_scale_x_object!==''&&e.details.detector_scale_y_object&&e.details.detector_scale_y_object!==''){x.dobjratio=' -s '+e.details.detector_scale_x_object+'x'+e.details.detector_scale_y_object}else{x.dobjratio=x.dratio}
|
||||
x.pipe += ' -r ' + x.detector_fps + x.dobjratio + x.cust_detect
|
||||
if(e.details.detector_fps_object){x.detector_fps_object = e.details.detector_fps_object}
|
||||
x.pipe += ' -r ' + x.detector_fps_object + x.dobjratio + x.cust_detect
|
||||
if(e.details.detector_h264 === '1'){
|
||||
x.pipe += h264Output
|
||||
}else{
|
||||
|
@ -884,6 +907,46 @@ module.exports = function(s,config,onFinish){
|
|||
x.pipe += ' -q:v 1 -an -c:v copy -f hls -tune zerolatency -g 1 -hls_time 2 -hls_list_size 3 -start_number 0 -live_start_index 3 -hls_allow_cache 0 -hls_flags +delete_segments+omit_endlist "'+e.sdir+'coProcessor.m3u8"'
|
||||
}
|
||||
}
|
||||
ffmpeg.buildTimelapseOutput = function(e,x){
|
||||
if(e.details.record_timelapse === '1'){
|
||||
x.record_timelapse_video_filters = []
|
||||
if(e.details.input_map_choices&&e.details.input_map_choices.record_timelapse){
|
||||
//add input feed map
|
||||
x.pipe += s.createFFmpegMap(e,e.details.input_map_choices.record_timelapse)
|
||||
}
|
||||
var flags = []
|
||||
if(e.details.record_timelapse_fps && e.details.record_timelapse_fps !== ''){
|
||||
flags.push('-r 1/' + e.details.record_timelapse_fps)
|
||||
}else{
|
||||
flags.push('-r 1/900') // 15 minutes
|
||||
}
|
||||
if(e.details.record_timelapse_vf && e.details.record_timelapse_vf !== '')flags.push('-vf ' + e.details.record_timelapse_vf)
|
||||
if(e.details.record_timelapse_scale_x && e.details.record_timelapse_scale_x !== '' && e.details.record_timelapse_scale_y && e.details.record_timelapse_scale_y !== '')flags.push(`-s ${e.details.record_timelapse_scale_x}x${e.details.record_timelapse_scale_y}`)
|
||||
//record - watermark for -vf
|
||||
if(e.details.record_timelapse_watermark&&e.details.record_timelapse_watermark=="1"&&e.details.record_timelapse_watermark_location&&e.details.record_timelapse_watermark_location!==''){
|
||||
switch(e.details.record_timelapse_watermark_position){
|
||||
case'tl'://top left
|
||||
x.record_timelapse_watermark_position='10:10'
|
||||
break;
|
||||
case'tr'://top right
|
||||
x.record_timelapse_watermark_position='main_w-overlay_w-10:10'
|
||||
break;
|
||||
case'bl'://bottom left
|
||||
x.record_timelapse_watermark_position='10:main_h-overlay_h-10'
|
||||
break;
|
||||
default://bottom right
|
||||
x.record_timelapse_watermark_position='(main_w-overlay_w-10)/2:(main_h-overlay_h-10)/2'
|
||||
break;
|
||||
}
|
||||
x.record_timelapse_video_filters.push('movie='+e.details.record_timelapse_watermark_location+'[watermark],[in][watermark]overlay='+x.record_timelapse_watermark_position+'[out]');
|
||||
}
|
||||
if(x.record_timelapse_video_filters.length > 0){
|
||||
var videoFilter = `-vf "${x.record_timelapse_video_filters.join(',').trim()}"`
|
||||
flags.push(videoFilter)
|
||||
}
|
||||
x.pipe += ` -f singlejpeg ${flags.join(' ')} -an -q:v 1 pipe:7`
|
||||
}
|
||||
}
|
||||
ffmpeg.assembleMainPieces = function(e,x){
|
||||
//create executeable FFMPEG command
|
||||
x.ffmpegCommandString = x.loglevel+x.input_fps;
|
||||
|
@ -900,6 +963,9 @@ module.exports = function(s,config,onFinish){
|
|||
case'mjpeg':
|
||||
x.ffmpegCommandString += ' -reconnect 1 -f mjpeg'+x.cust_input+x.hwaccel+' -i "'+e.url+'"';
|
||||
break;
|
||||
case'mxpeg':
|
||||
x.ffmpegCommandString += ' -reconnect 1 -f mxg'+x.cust_input+x.hwaccel+' -i "'+e.url+'"';
|
||||
break;
|
||||
case'rtmp':
|
||||
if(!e.details.rtmp_key)e.details.rtmp_key = ''
|
||||
x.ffmpegCommandString += x.cust_input+x.hwaccel+` -i "rtmp://127.0.0.1:1935/${e.ke + '_' + e.mid + '_' + e.details.rtmp_key}"`;
|
||||
|
@ -941,13 +1007,14 @@ module.exports = function(s,config,onFinish){
|
|||
ffmpeg.buildAudioDetector(e,x)
|
||||
ffmpeg.buildMainDetector(e,x)
|
||||
ffmpeg.buildCoProcessorFeed(e,x)
|
||||
ffmpeg.buildTimelapseOutput(e,x)
|
||||
s.onFfmpegCameraStringCreationExtensions.forEach(function(extender){
|
||||
extender(e,x)
|
||||
})
|
||||
ffmpeg.assembleMainPieces(e,x)
|
||||
ffmpeg.createPipeArray(e,x)
|
||||
//hold ffmpeg command for log stream
|
||||
s.group[e.ke].mon[e.mid].ffmpeg = x.ffmpegCommandString
|
||||
s.group[e.ke].activeMonitors[e.mid].ffmpeg = x.ffmpegCommandString
|
||||
//clean the string of spatial impurities and split for spawn()
|
||||
x.ffmpegCommandString = s.splitForFFPMEG(x.ffmpegCommandString)
|
||||
//launch that bad boy
|
||||
|
|
|
@ -140,27 +140,27 @@ module.exports = function(s,config,lang,ffmpeg){
|
|||
if(commandString === x.input){
|
||||
return false
|
||||
}
|
||||
s.group[e.ke].mon[e.mid].coProcessorCmd = commandString
|
||||
s.group[e.ke].activeMonitors[e.mid].coProcessorCmd = commandString
|
||||
return spawn(config.ffmpegDir,s.splitForFFPMEG((commandString).replace(/\s+/g,' ').trim()),{detached: true,stdio:x.stdioPipes})
|
||||
}
|
||||
s.coSpawnLauncher = function(e){
|
||||
if(s.group[e.ke].mon[e.id].isStarted === true && e.coProcessor === true){
|
||||
if(s.group[e.ke].activeMonitors[e.id].isStarted === true && e.coProcessor === true){
|
||||
s.coSpawnClose(e)
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor = s.ffmpegCoProcessor(e)
|
||||
if(s.group[e.ke].mon[e.id].coSpawnProcessor === false){
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor = s.ffmpegCoProcessor(e)
|
||||
if(s.group[e.ke].activeMonitors[e.id].coSpawnProcessor === false){
|
||||
return
|
||||
}
|
||||
s.userLog(e,{type:lang['coProcessor Started'],msg:{msg:lang.coProcessorTextStarted,cmd:s.group[e.ke].mon[e.id].coProcessorCmd}});
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessorExit = function(){
|
||||
s.userLog(e,{type:lang['coProcess Unexpected Exit'],msg:{msg:lang['coProcess Crashed for Monitor']+' : '+e.id,cmd:s.group[e.ke].mon[e.id].coProcessorCmd}});
|
||||
s.userLog(e,{type:lang['coProcessor Started'],msg:{msg:lang.coProcessorTextStarted,cmd:s.group[e.ke].activeMonitors[e.id].coProcessorCmd}});
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessorExit = function(){
|
||||
s.userLog(e,{type:lang['coProcess Unexpected Exit'],msg:{msg:lang['coProcess Crashed for Monitor']+' : '+e.id,cmd:s.group[e.ke].activeMonitors[e.id].coProcessorCmd}});
|
||||
setTimeout(function(){
|
||||
s.coSpawnLauncher(e)
|
||||
},2000)
|
||||
}
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.on('end',s.group[e.ke].mon[e.id].coSpawnProcessorExit)
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.on('exit',s.group[e.ke].mon[e.id].coSpawnProcessorExit)
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.on('end',s.group[e.ke].activeMonitors[e.id].coSpawnProcessorExit)
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.on('exit',s.group[e.ke].activeMonitors[e.id].coSpawnProcessorExit)
|
||||
var checkLog = function(d,x){return d.indexOf(x)>-1;}
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.stderr.on('data',function(d){
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.stderr.on('data',function(d){
|
||||
d=d.toString();
|
||||
switch(true){
|
||||
case checkLog(d,'deprecated pixel format used'):
|
||||
|
@ -176,34 +176,34 @@ module.exports = function(s,config,lang,ffmpeg){
|
|||
s.userLog(e,{type:lang.coProcessor,msg:d});
|
||||
})
|
||||
if(e.frame_to_stream){
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.stdout.on('data',e.frame_to_stream)
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.stdout.on('data',e.frame_to_stream)
|
||||
}
|
||||
if(e.details.detector === '1'){
|
||||
s.ocvTx({f:'init_monitor',id:e.id,ke:e.ke})
|
||||
//frames from motion detect
|
||||
if(e.details.detector_pam === '1'){
|
||||
s.createPamDiffEngine(e)
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[3].pipe(s.group[e.ke].mon[e.id].p2p).pipe(s.group[e.ke].mon[e.id].pamDiff)
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.stdio[3].pipe(s.group[e.ke].activeMonitors[e.id].p2p).pipe(s.group[e.ke].activeMonitors[e.id].pamDiff)
|
||||
if(e.details.detector_use_detect_object === '1'){
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[4].on('data',function(d){
|
||||
s.group[e.ke].mon[e.id].lastJpegDetectorFrame = d
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.stdio[4].on('data',function(d){
|
||||
s.group[e.ke].activeMonitors[e.id].lastJpegDetectorFrame = d
|
||||
})
|
||||
}
|
||||
}else if(s.isAtleatOneDetectorPluginConnected){
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.stdio[3].on('data',function(d){
|
||||
s.ocvTx({f:'frame',mon:s.group[e.ke].mon_conf[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d});
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.stdio[3].on('data',function(d){
|
||||
s.ocvTx({f:'frame',mon:s.group[e.ke].rawMonitorConfigurations[e.id].details,ke:e.ke,id:e.id,time:s.formattedTime(),frame:d});
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
s.coSpawnClose = function(e){
|
||||
if(s.group[e.ke].mon[e.id].coSpawnProcessor){
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.removeListener('end',s.group[e.ke].mon[e.id].coSpawnProcessorExit);
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.removeListener('exit',s.group[e.ke].mon[e.id].coSpawnProcessorExit);
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.stdin.pause()
|
||||
s.group[e.ke].mon[e.id].coSpawnProcessor.kill()
|
||||
delete(s.group[e.ke].mon[e.id].coSpawnProcessor)
|
||||
if(s.group[e.ke].activeMonitors[e.id].coSpawnProcessor){
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.removeListener('end',s.group[e.ke].activeMonitors[e.id].coSpawnProcessorExit);
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.removeListener('exit',s.group[e.ke].activeMonitors[e.id].coSpawnProcessorExit);
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.stdin.pause()
|
||||
s.group[e.ke].activeMonitors[e.id].coSpawnProcessor.kill()
|
||||
delete(s.group[e.ke].activeMonitors[e.id].coSpawnProcessor)
|
||||
s.userLog(e,{type:lang['coProcessor Stopped'],msg:{msg:lang.coProcessorTextStopped+' : '+e.id}});
|
||||
}
|
||||
}
|
||||
|
|
13
libs/fileBin.js
Normal file
13
libs/fileBin.js
Normal file
|
@ -0,0 +1,13 @@
|
|||
var fs = require('fs')
|
||||
var moment = require('moment')
|
||||
module.exports = function(s,config,lang,app,io){
|
||||
s.getFileBinDirectory = function(e){
|
||||
if(e.mid&&!e.id){e.id=e.mid}
|
||||
s.checkDetails(e)
|
||||
if(e.details&&e.details.dir&&e.details.dir!==''){
|
||||
return s.checkCorrectPathEnding(e.details.dir)+e.ke+'/'+e.id+'/'
|
||||
}else{
|
||||
return s.dir.fileBin+e.ke+'/'+e.id+'/';
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
var fs = require('fs');
|
||||
module.exports = function(s,config){
|
||||
module.exports = function(s,config,lang){
|
||||
//directories
|
||||
s.group = {}
|
||||
if(!config.windowsTempDir&&s.isWin===true){config.windowsTempDir='C:/Windows/Temp'}
|
||||
|
@ -40,10 +40,44 @@ module.exports = function(s,config){
|
|||
fs.mkdirSync(s.dir.fileBin);
|
||||
}
|
||||
//additional storage areas
|
||||
s.listOfStorage = [{
|
||||
name: lang['Default'],
|
||||
value: ""
|
||||
}]
|
||||
s.dir.addStorage.forEach(function(v,n){
|
||||
v.path = s.checkCorrectPathEnding(v.path)
|
||||
if(!fs.existsSync(v.path)){
|
||||
fs.mkdirSync(v.path);
|
||||
}
|
||||
s.listOfStorage.push({
|
||||
name: v.name,
|
||||
value: v.path
|
||||
})
|
||||
})
|
||||
//get audio files list
|
||||
s.listOfAudioFiles = [
|
||||
{
|
||||
name:lang['No Sound'],
|
||||
value:""
|
||||
}
|
||||
]
|
||||
fs.readdirSync(s.mainDirectory + '/web/libs/audio').forEach(function(file){
|
||||
s.listOfAudioFiles.push({
|
||||
name: file,
|
||||
value: file
|
||||
})
|
||||
})
|
||||
//get themes list
|
||||
s.listOfThemes = [
|
||||
{
|
||||
name:lang['Default'],
|
||||
value:""
|
||||
}
|
||||
]
|
||||
fs.readdirSync(s.mainDirectory + '/web/libs/themes').forEach(function(folder){
|
||||
s.listOfThemes.push({
|
||||
name: folder,
|
||||
value: folder
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,12 +1,6 @@
|
|||
var exec = require('child_process').exec;
|
||||
var spawn = require('child_process').spawn;
|
||||
module.exports = function(s,config,lang,io){
|
||||
s.sendDiskUsedAmountToClients = function(e){
|
||||
//send the amount used disk space to connected users
|
||||
if(s.group[e.ke]&&s.group[e.ke].init){
|
||||
s.tx({f:'diskUsed',size:s.group[e.ke].usedSpace,limit:s.group[e.ke].sizeLimit},'GRP_'+e.ke);
|
||||
}
|
||||
}
|
||||
s.heartBeat = function(){
|
||||
setTimeout(s.heartBeat, 8000);
|
||||
io.sockets.emit('ping',{beat:1});
|
||||
|
@ -34,14 +28,20 @@ module.exports = function(s,config,lang,io){
|
|||
d = d.replace(/(\r\n|\n|\r)/gm, "").replace(/%/g, "")
|
||||
}
|
||||
callback(d)
|
||||
});
|
||||
s.onGetCpuUsageExtensions.forEach(function(extender){
|
||||
extender(d)
|
||||
})
|
||||
})
|
||||
} else if(k.cmd){
|
||||
exec(k.cmd,{encoding:'utf8',detached: true},function(err,d){
|
||||
if(s.isWin===true){
|
||||
d=d.replace(/(\r\n|\n|\r)/gm,"").replace(/%/g,"")
|
||||
}
|
||||
callback(d)
|
||||
});
|
||||
s.onGetCpuUsageExtensions.forEach(function(extender){
|
||||
extender(d)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
callback(0)
|
||||
}
|
||||
|
@ -68,7 +68,10 @@ module.exports = function(s,config,lang,io){
|
|||
d=(parseInt(d.split('=')[1])/(s.totalmem/1000))*100
|
||||
}
|
||||
callback(d)
|
||||
});
|
||||
s.onGetRamUsageExtensions.forEach(function(extender){
|
||||
extender(d)
|
||||
})
|
||||
})
|
||||
}else{
|
||||
callback(0)
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
var fs = require('fs')
|
||||
module.exports = function(s,config){
|
||||
if(!config.language){
|
||||
config.language='en_CA'
|
||||
|
@ -9,19 +10,19 @@ module.exports = function(s,config){
|
|||
console.log('There was an error loading your language file.')
|
||||
var lang = require(s.location.languages+'/en_CA.json');
|
||||
}
|
||||
s.location.definitions = s.mainDirectory+'/definitions'
|
||||
try{
|
||||
var definitions = require(s.location.definitions+'/'+config.language+'.json');
|
||||
}catch(er){
|
||||
console.error(er)
|
||||
console.log('There was an error loading your language file.')
|
||||
var definitions = require(s.location.definitions+'/en_CA.json');
|
||||
}
|
||||
//load languages dynamically
|
||||
s.copySystemDefaultLanguage = function(){
|
||||
//en_CA
|
||||
return Object.assign(lang,{})
|
||||
}
|
||||
s.listOfPossibleLanguages = []
|
||||
fs.readdirSync(s.mainDirectory + '/languages').forEach(function(filename){
|
||||
var name = filename.replace('.json','')
|
||||
s.listOfPossibleLanguages.push({
|
||||
"name": name,
|
||||
"value": name,
|
||||
})
|
||||
})
|
||||
s.loadedLanguages={}
|
||||
s.loadedLanguages[config.language] = s.copySystemDefaultLanguage()
|
||||
s.getLanguageFile = function(rule){
|
||||
|
@ -41,29 +42,5 @@ module.exports = function(s,config){
|
|||
}
|
||||
return file
|
||||
}
|
||||
//load defintions dynamically
|
||||
s.copySystemDefaultDefinitions = function(){
|
||||
//en_CA
|
||||
return Object.assign(definitions,{})
|
||||
}
|
||||
s.loadedDefinitons={}
|
||||
s.loadedDefinitons[config.language] = s.copySystemDefaultDefinitions()
|
||||
s.getDefinitonFile = function(rule){
|
||||
if(rule && rule !== ''){
|
||||
var file = s.loadedDefinitons[file]
|
||||
if(!file){
|
||||
try{
|
||||
s.loadedDefinitons[rule] = require(s.location.definitions+'/'+rule+'.json')
|
||||
s.loadedDefinitons[rule] = Object.assign(s.copySystemDefaultDefinitions(),s.loadedDefinitons[rule])
|
||||
file = s.loadedDefinitons[rule]
|
||||
}catch(err){
|
||||
file = s.copySystemDefaultDefinitions()
|
||||
}
|
||||
}
|
||||
}else{
|
||||
file = s.copySystemDefaultDefinitions()
|
||||
}
|
||||
return file
|
||||
}
|
||||
return lang
|
||||
}
|
||||
|
|
1195
libs/monitor.js
1195
libs/monitor.js
File diff suppressed because it is too large
Load diff
|
@ -50,7 +50,7 @@ module.exports = function(s,config,lang){
|
|||
var onEventTriggerForDiscord = function(d,filter){
|
||||
// d = event object
|
||||
//discord bot
|
||||
if(filter.discord && d.mon.details.detector_discordbot === '1' && !s.group[d.ke].mon[d.id].detector_discordbot){
|
||||
if(filter.discord && s.group[d.ke].discordBot && d.mon.details.detector_discordbot === '1' && !s.group[d.ke].activeMonitors[d.id].detector_discordbot){
|
||||
var detector_discordbot_timeout
|
||||
if(!d.mon.details.detector_discordbot_timeout||d.mon.details.detector_discordbot_timeout===''){
|
||||
detector_discordbot_timeout = 1000*60*10;
|
||||
|
@ -58,16 +58,16 @@ module.exports = function(s,config,lang){
|
|||
detector_discordbot_timeout = parseFloat(d.mon.details.detector_discordbot_timeout)*1000*60;
|
||||
}
|
||||
//lock mailer so you don't get emailed on EVERY trigger event.
|
||||
s.group[d.ke].mon[d.id].detector_discordbot=setTimeout(function(){
|
||||
s.group[d.ke].activeMonitors[d.id].detector_discordbot = setTimeout(function(){
|
||||
//unlock so you can mail again.
|
||||
clearTimeout(s.group[d.ke].mon[d.id].detector_discordbot);
|
||||
delete(s.group[d.ke].mon[d.id].detector_discordbot);
|
||||
},detector_discordbot_timeout);
|
||||
clearTimeout(s.group[d.ke].activeMonitors[d.id].detector_discordbot);
|
||||
delete(s.group[d.ke].activeMonitors[d.id].detector_discordbot);
|
||||
},detector_discordbot_timeout)
|
||||
var files = []
|
||||
var sendAlert = function(){
|
||||
s.discordMsg({
|
||||
author: {
|
||||
name: s.group[d.ke].mon_conf[d.id].name,
|
||||
name: s.group[d.ke].rawMonitorConfigurations[d.id].name,
|
||||
icon_url: config.iconURL
|
||||
},
|
||||
title: lang.Event+' - '+d.screenshotName,
|
||||
|
@ -84,7 +84,7 @@ module.exports = function(s,config,lang){
|
|||
s.mergeDetectorBufferChunks(d,function(mergedFilepath,filename){
|
||||
s.discordMsg({
|
||||
author: {
|
||||
name: s.group[d.ke].mon_conf[d.id].name,
|
||||
name: s.group[d.ke].rawMonitorConfigurations[d.id].name,
|
||||
icon_url: config.iconURL
|
||||
},
|
||||
title: filename,
|
||||
|
@ -102,8 +102,10 @@ module.exports = function(s,config,lang){
|
|||
],d.ke)
|
||||
})
|
||||
}
|
||||
s.getRawSnapshotFromMonitor(d.mon,function(data){
|
||||
if((data[data.length-2] === 0xFF && data[data.length-1] === 0xD9)){
|
||||
s.getRawSnapshotFromMonitor(d.mon,{
|
||||
secondsInward: d.mon.details.snap_seconds_inward
|
||||
},function(data){
|
||||
if(data[data.length - 2] === 0xFF && data[data.length - 1] === 0xD9){
|
||||
d.screenshotBuffer = data
|
||||
files.push({
|
||||
attachment: d.screenshotBuffer,
|
||||
|
@ -251,7 +253,7 @@ module.exports = function(s,config,lang){
|
|||
filter.mail = true
|
||||
}
|
||||
var onEventTriggerForEmail = function(d,filter){
|
||||
if(filter.mail && config.mail && !s.group[d.ke].mon[d.id].detector_mail && d.mon.details.detector_mail === '1'){
|
||||
if(filter.mail && config.mail && !s.group[d.ke].activeMonitors[d.id].detector_mail && d.mon.details.detector_mail === '1'){
|
||||
s.sqlQuery('SELECT mail FROM Users WHERE ke=? AND details NOT LIKE ?',[d.ke,'%"sub"%'],function(err,r){
|
||||
r=r[0];
|
||||
var detector_mail_timeout
|
||||
|
@ -261,10 +263,10 @@ module.exports = function(s,config,lang){
|
|||
detector_mail_timeout = parseFloat(d.mon.details.detector_mail_timeout)*1000*60;
|
||||
}
|
||||
//lock mailer so you don't get emailed on EVERY trigger event.
|
||||
s.group[d.ke].mon[d.id].detector_mail=setTimeout(function(){
|
||||
s.group[d.ke].activeMonitors[d.id].detector_mail=setTimeout(function(){
|
||||
//unlock so you can mail again.
|
||||
clearTimeout(s.group[d.ke].mon[d.id].detector_mail);
|
||||
delete(s.group[d.ke].mon[d.id].detector_mail);
|
||||
clearTimeout(s.group[d.ke].activeMonitors[d.id].detector_mail);
|
||||
delete(s.group[d.ke].activeMonitors[d.id].detector_mail);
|
||||
},detector_mail_timeout);
|
||||
var files = []
|
||||
var mailOptions = {
|
||||
|
@ -287,36 +289,42 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
if(d.mon.details.detector_mail_send_video === '1'){
|
||||
s.mergeDetectorBufferChunks(d,function(mergedFilepath,filename){
|
||||
s.nodemailer.sendMail({
|
||||
from: config.mail.from,
|
||||
to: r.mail,
|
||||
subject: filename,
|
||||
html: '',
|
||||
attachments: [
|
||||
{
|
||||
filename: filename,
|
||||
content: fs.readFileSync(mergedFilepath)
|
||||
}
|
||||
]
|
||||
}, (error, info) => {
|
||||
if (error) {
|
||||
s.systemLog(lang.MailError,error)
|
||||
return false;
|
||||
fs.readFile(mergedFilepath,function(err,buffer){
|
||||
if(buffer){
|
||||
s.nodemailer.sendMail({
|
||||
from: config.mail.from,
|
||||
to: r.mail,
|
||||
subject: filename,
|
||||
html: '',
|
||||
attachments: [
|
||||
{
|
||||
filename: filename,
|
||||
content: buffer
|
||||
}
|
||||
]
|
||||
}, (error, info) => {
|
||||
if (error) {
|
||||
s.systemLog(lang.MailError,error)
|
||||
return false;
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
if(d.screenshotBuffer){
|
||||
files.push({
|
||||
filename: d.screenshotName+'.jpg',
|
||||
filename: d.screenshotName + '.jpg',
|
||||
content: d.screenshotBuffer
|
||||
})
|
||||
sendMail()
|
||||
}else{
|
||||
s.getRawSnapshotFromMonitor(d.mon,function(data){
|
||||
s.getRawSnapshotFromMonitor(d.mon,{
|
||||
secondsInward: d.mon.details.snap_seconds_inward
|
||||
},function(data){
|
||||
d.screenshotBuffer = data
|
||||
files.push({
|
||||
filename: d.screenshotName+'.jpg',
|
||||
filename: d.screenshotName + '.jpg',
|
||||
content: data
|
||||
})
|
||||
sendMail()
|
||||
|
|
107
libs/plugins.js
107
libs/plugins.js
|
@ -1,7 +1,12 @@
|
|||
var socketIOclient = require('socket.io-client');
|
||||
module.exports = function(s,config,lang){
|
||||
module.exports = function(s,config,lang,io){
|
||||
//send data to detector plugin
|
||||
s.ocvTx = function(data){
|
||||
// chaining coming in future update
|
||||
s.sendToAllDetectors(data)
|
||||
}
|
||||
//function for receiving detector data
|
||||
s.pluginEventController=function(d){
|
||||
s.pluginEventController = function(d){
|
||||
switch(d.f){
|
||||
case'trigger':
|
||||
s.triggerEvent(d)
|
||||
|
@ -22,16 +27,32 @@ module.exports = function(s,config,lang){
|
|||
s.detectorPluginArray = []
|
||||
s.isAtleatOneDetectorPluginConnected = false
|
||||
s.addDetectorPlugin = function(name,d){
|
||||
if(config.useOldPluginConnectionMethod === true){
|
||||
s.ocv = {
|
||||
started: s.timeObject(),
|
||||
id: d.id,
|
||||
plug: d.plug,
|
||||
notice: d.notice,
|
||||
isClientPlugin: d.isClientPlugin,
|
||||
isHostPlugin: d.isHostPlugin,
|
||||
connectionType: d.connectionType
|
||||
}
|
||||
}
|
||||
s.connectedDetectorPlugins[d.plug] = {
|
||||
started: s.timeObject(),
|
||||
id: d.id,
|
||||
plug: d.plug,
|
||||
notice: d.notice,
|
||||
isClientPlugin: d.isClientPlugin,
|
||||
isHostPlugin: d.isHostPlugin,
|
||||
connectionType: d.connectionType
|
||||
}
|
||||
s.resetDetectorPluginArray()
|
||||
}
|
||||
s.removeDetectorPlugin = function(name){
|
||||
if(config.oldPluginConnectionMethod === true && s.ocv && s.ocv.plug === name){
|
||||
delete(s.ocv)
|
||||
}
|
||||
delete(s.connectedDetectorPlugins[name])
|
||||
s.resetDetectorPluginArray(name)
|
||||
}
|
||||
|
@ -48,6 +69,7 @@ module.exports = function(s,config,lang){
|
|||
}else{
|
||||
s.isAtleatOneDetectorPluginConnected = false
|
||||
}
|
||||
s.debugLog(`resetDetectorPluginArray : ${JSON.stringify(pluginArray)}`)
|
||||
s.detectorPluginArray = pluginArray
|
||||
}
|
||||
s.sendToAllDetectors = function(data){
|
||||
|
@ -67,7 +89,7 @@ module.exports = function(s,config,lang){
|
|||
// s.sendToDetectorsInChain = function(){
|
||||
//
|
||||
// }
|
||||
s.pluginInitiatorSuccess=function(mode,d,cn){
|
||||
s.pluginInitiatorSuccess = function(mode,d,cn){
|
||||
s.systemLog('pluginInitiatorSuccess',d)
|
||||
if(!s.connectedPlugins[d.plug]){
|
||||
s.connectedPlugins[d.plug]={
|
||||
|
@ -83,6 +105,7 @@ module.exports = function(s,config,lang){
|
|||
s.systemLog('Connected to plugin : Detector - '+d.plug+' - '+d.type)
|
||||
switch(d.type){
|
||||
default:case'detector':
|
||||
if(config.oldPluginConnectionMethod)cn.ocv = 1
|
||||
cn.detectorPlugin = d.plug
|
||||
s.addDetectorPlugin(d.plug,{
|
||||
id: cn.id,
|
||||
|
@ -99,10 +122,10 @@ module.exports = function(s,config,lang){
|
|||
switch(d.type){
|
||||
default:case'detector':
|
||||
s.addDetectorPlugin(d.plug,{
|
||||
id:"host",
|
||||
plug:d.plug,
|
||||
notice:d.notice,
|
||||
isHostPlugin:true,
|
||||
id: "host",
|
||||
plug: d.plug,
|
||||
notice: d.notice,
|
||||
isHostPlugin: true,
|
||||
connectionType: d.connectionType
|
||||
})
|
||||
s.tx({f:'detector_plugged',plug:d.plug,notice:d.notice},'CPU')
|
||||
|
@ -145,12 +168,12 @@ module.exports = function(s,config,lang){
|
|||
});
|
||||
socket.on('init',function(d){
|
||||
s.systemLog('Initialize Plugin : Host',d)
|
||||
if(d.ok===true){
|
||||
if(d.ok === true){
|
||||
s.pluginInitiatorSuccess("host",d)
|
||||
}else{
|
||||
s.pluginInitiatorFail("host",d)
|
||||
}
|
||||
});
|
||||
})
|
||||
socket.on('ocv',s.pluginEventController);
|
||||
socket.on('disconnect', function(){
|
||||
s.connectedPlugins[v.id].plugged=false
|
||||
|
@ -174,4 +197,70 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
})
|
||||
}
|
||||
var onWebSocketDisconnection = function(cn){
|
||||
if(cn.pluginEngine){
|
||||
s.connectedPlugins[cn.pluginEngine].plugged = false
|
||||
s.tx({f:'plugin_engine_unplugged',plug:cn.pluginEngine},'CPU')
|
||||
}
|
||||
if(cn.detectorPlugin){
|
||||
s.tx({f:'detector_unplugged',plug:cn.detectorPlugin},'CPU')
|
||||
s.removeDetectorPlugin(cn.detectorPlugin)
|
||||
s.sendDetectorInfoToClient({f:'detector_plugged'},function(data){
|
||||
s.tx(data,'CPU')
|
||||
})
|
||||
}
|
||||
if(cn.ocv && s.ocv){
|
||||
s.tx({f:'detector_unplugged',plug:s.ocv.plug},'CPU')
|
||||
delete(s.ocv);
|
||||
}
|
||||
}
|
||||
var onSocketAuthentication = function(r,cn,d,tx){
|
||||
if(s.isAtleatOneDetectorPluginConnected){
|
||||
s.sendDetectorInfoToClient({f:'detector_plugged'},tx)
|
||||
s.ocvTx({f:'readPlugins',ke:d.ke})
|
||||
}
|
||||
if(config.oldPluginConnectionMethod && s.ocv){
|
||||
tx({f:'detector_plugged',plug:s.ocv.plug,notice:s.ocv.notice})
|
||||
}
|
||||
}
|
||||
var onWebSocketConnection = function(cn){
|
||||
cn.on('ocv',function(d){
|
||||
if(!cn.pluginEngine && d.f === 'init'){
|
||||
if(config.pluginKeys[d.plug] === d.pluginKey){
|
||||
s.pluginInitiatorSuccess("client",d,cn)
|
||||
}else{
|
||||
s.pluginInitiatorFail("client",d,cn)
|
||||
}
|
||||
}else{
|
||||
if(config.pluginKeys[d.plug] === d.pluginKey){
|
||||
s.pluginEventController(d)
|
||||
}else{
|
||||
cn.disconnect()
|
||||
}
|
||||
}
|
||||
})
|
||||
cn.on('f',function(d){
|
||||
if((d.id || d.uid || d.mid) && cn.ke){
|
||||
switch(d.f){
|
||||
case'ocv_in':
|
||||
s.ocvTx(d.data)
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
if(config.oldPluginConnectionMethod === undefined)config.oldPluginConnectionMethod = false
|
||||
if(config.oldPluginConnectionMethod === true){
|
||||
s.ocvTx = function(data){
|
||||
if(!s.ocv){return}
|
||||
if(s.ocv.isClientPlugin === true){
|
||||
s.tx(data,s.ocv.id)
|
||||
}else{
|
||||
s.connectedPlugins[s.ocv.plug].tx(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
s.onSocketAuthentication(onSocketAuthentication)
|
||||
s.onWebSocketDisconnection(onWebSocketDisconnection)
|
||||
s.onWebSocketConnection(onWebSocketConnection)
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
var os = require('os')
|
||||
module.exports = function(process,__dirname){
|
||||
var packageJson = require('../package.json')
|
||||
process.send = process.send || function () {};
|
||||
process.on('uncaughtException', function (err) {
|
||||
console.error('Uncaught Exception occured!');
|
||||
|
@ -32,5 +33,9 @@ module.exports = function(process,__dirname){
|
|||
//directory path for this file
|
||||
mainDirectory : __dirname
|
||||
}
|
||||
s.packageJson = packageJson
|
||||
if(packageJson.mainDirectory){
|
||||
s.mainDirectory = require('path').resolve('.')
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
const chalk = require('chalk');
|
||||
|
||||
LOG_TYPES = {
|
||||
NONE: 0,
|
||||
ERROR: 1,
|
||||
|
@ -24,25 +22,25 @@ const logTime = () => {
|
|||
const log = (...args) => {
|
||||
if (logType < LOG_TYPES.NORMAL) return;
|
||||
|
||||
console.log(logTime(), process.pid, chalk.bold.green('[INFO]'), ...args);
|
||||
console.log(logTime(), ...args);
|
||||
};
|
||||
|
||||
const error = (...args) => {
|
||||
if (logType < LOG_TYPES.ERROR) return;
|
||||
|
||||
console.log(logTime(), process.pid, chalk.bold.red('[ERROR]'), ...args);
|
||||
console.error(logTime(), ...args);
|
||||
};
|
||||
|
||||
const debug = (...args) => {
|
||||
if (logType < LOG_TYPES.DEBUG) return;
|
||||
|
||||
console.log(logTime(), process.pid, chalk.bold.blue('[DEBUG]'), ...args);
|
||||
console.log(logTime(), ...args);
|
||||
};
|
||||
|
||||
const ffdebug = (...args) => {
|
||||
if (logType < LOG_TYPES.FFDEBUG) return;
|
||||
|
||||
console.log(logTime(), process.pid, chalk.bold.blue('[FFDEBUG]'), ...args);
|
||||
console.log(logTime(), ...args);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
|
@ -50,4 +48,4 @@ module.exports = {
|
|||
setLogType,
|
||||
|
||||
log, error, debug, ffdebug
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ class NodeRtmpServer {
|
|||
session.socket.destroy();
|
||||
context.sessions.delete(id);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@ module.exports = function(s,config,lang,app,io){
|
|||
var schedule = Object.assign(row,{})
|
||||
if(!s.schedules[schedule.ke])s.schedules[schedule.ke] = {}
|
||||
s.checkDetails(schedule)
|
||||
schedule.timezoneOffset = parseInt(schedule.details.timezone) || 0
|
||||
schedule.details.days.forEach(function(dayNumber,key){
|
||||
schedule.details.days[key] = parseInt(dayNumber)
|
||||
})
|
||||
if(!s.schedules[schedule.ke][schedule.name]){
|
||||
s.schedules[schedule.ke][schedule.name] = schedule
|
||||
}else{
|
||||
|
@ -22,7 +26,10 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
}
|
||||
//check time in schedule
|
||||
s.checkTimeAgainstSchedule = function(start,end,callback){
|
||||
var checkTimeAgainstSchedule = function(schedule,callback){
|
||||
var start = schedule.start
|
||||
var end = schedule.end
|
||||
if(!callback)callback = function(){}
|
||||
try{
|
||||
if(
|
||||
start
|
||||
|
@ -32,16 +39,17 @@ module.exports = function(s,config,lang,app,io){
|
|||
var startHour = parseInt(startSplit[0])
|
||||
var startMin = parseInt(startSplit[1])
|
||||
checkStartTime.setHours(startHour)
|
||||
checkStartTime.setMinutes(startMin)
|
||||
checkStartTime.setMinutes(startMin - schedule.timezoneOffset)
|
||||
if(end){
|
||||
var checkEndTime = new Date()
|
||||
var endSplit = end.split(':')
|
||||
var endHour = parseInt(endSplit[0])
|
||||
var endMin = parseInt(endSplit[1])
|
||||
checkEndTime.setHours(endHour)
|
||||
checkEndTime.setMinutes(endMin)
|
||||
checkEndTime.setMinutes(endMin - schedule.timezoneOffset)
|
||||
}
|
||||
var currentDate = new Date()
|
||||
currentDate.setMinutes(currentDate.getMinutes() - schedule.timezoneOffset)
|
||||
if(
|
||||
(
|
||||
currentDate >= checkStartTime &&
|
||||
|
@ -50,6 +58,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
currentDate >= checkStartTime && !end
|
||||
){
|
||||
callback()
|
||||
return true
|
||||
}else{
|
||||
callback({
|
||||
currentDate : currentDate,
|
||||
|
@ -58,12 +67,45 @@ module.exports = function(s,config,lang,app,io){
|
|||
})
|
||||
}
|
||||
}else{
|
||||
callback()
|
||||
callback({}) //no start time selected, failed
|
||||
}
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
callback()
|
||||
callback(err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
//check days in schedule
|
||||
var checkDaysAgainstSchedule = function(schedule,callback){
|
||||
var days = schedule.details.days
|
||||
if(!callback)callback = function(){}
|
||||
try{
|
||||
if(
|
||||
days
|
||||
){
|
||||
var currentDate = new Date()
|
||||
currentDate.setMinutes(currentDate.getMinutes() - schedule.timezoneOffset)
|
||||
var currentDay = currentDate.getDay()
|
||||
if(
|
||||
days.indexOf(currentDay) > -1 // if currentDay of week is found in schedule selection
|
||||
){
|
||||
callback()
|
||||
return true
|
||||
}else{
|
||||
callback({
|
||||
currentDate: currentDate,
|
||||
currentDay: currentDay
|
||||
})
|
||||
}
|
||||
}else{
|
||||
callback() //no days selected, succeed
|
||||
return true
|
||||
}
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
callback(err)
|
||||
}
|
||||
return false
|
||||
}
|
||||
//check all Schedules
|
||||
s.checkSchedules = function(v,callback){
|
||||
|
@ -73,25 +115,25 @@ module.exports = function(s,config,lang,app,io){
|
|||
scheduleNames.forEach(function(name){
|
||||
var schedule = s.schedules[key][name]
|
||||
if(!schedule.active && schedule.enabled === 1 && schedule.start && schedule.details.monitorStates){
|
||||
s.checkTimeAgainstSchedule(schedule.start,schedule.end,function(err){
|
||||
if(!err){
|
||||
schedule.active = true
|
||||
var monitorStates = schedule.details.monitorStates
|
||||
monitorStates.forEach(function(stateName){
|
||||
s.activateMonitorStates(key,stateName,{
|
||||
ke: key,
|
||||
uid: 'System',
|
||||
details: {},
|
||||
permissions: {},
|
||||
lang: lang
|
||||
},function(endData){
|
||||
// console.log(endData)
|
||||
})
|
||||
var timePasses = checkTimeAgainstSchedule(schedule)
|
||||
var daysPasses = checkDaysAgainstSchedule(schedule)
|
||||
if(timePasses && daysPasses){
|
||||
schedule.active = true
|
||||
var monitorStates = schedule.details.monitorStates
|
||||
monitorStates.forEach(function(stateName){
|
||||
s.activateMonitorStates(key,stateName,{
|
||||
ke: key,
|
||||
uid: 'System',
|
||||
details: {},
|
||||
permissions: {},
|
||||
lang: lang
|
||||
},function(endData){
|
||||
// console.log(endData)
|
||||
})
|
||||
}else{
|
||||
schedule.active = false
|
||||
}
|
||||
})
|
||||
})
|
||||
}else{
|
||||
schedule.active = false
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
113
libs/socketio.js
113
libs/socketio.js
|
@ -7,11 +7,6 @@ var jsonfile = require("jsonfile");
|
|||
var onvif = require("node-onvif");
|
||||
module.exports = function(s,config,lang,io){
|
||||
s.clientSocketConnection = {}
|
||||
//send data to detector plugin
|
||||
s.ocvTx=function(data){
|
||||
// chaining coming in future update
|
||||
s.sendToAllDetectors(data)
|
||||
}
|
||||
//send data to socket client function
|
||||
s.tx = function(z,y,x){if(x){return x.broadcast.to(y).emit('f',z)};io.to(y).emit('f',z);}
|
||||
s.txToDashcamUsers = function(data,groupKey){
|
||||
|
@ -53,25 +48,9 @@ module.exports = function(s,config,lang,io){
|
|||
////socket controller
|
||||
io.on('connection', function (cn) {
|
||||
var tx;
|
||||
//set "client" detector plugin event function
|
||||
cn.on('ocv',function(d){
|
||||
if(!cn.pluginEngine && d.f === 'init'){
|
||||
if(config.pluginKeys[d.plug] === d.pluginKey){
|
||||
s.pluginInitiatorSuccess("client",d,cn)
|
||||
}else{
|
||||
s.pluginInitiatorFail("client",d,cn)
|
||||
}
|
||||
}else{
|
||||
if(config.pluginKeys[d.plug] === d.pluginKey){
|
||||
s.pluginEventController(d)
|
||||
}else{
|
||||
cn.disconnect()
|
||||
}
|
||||
}
|
||||
})
|
||||
//unique h265 socket stream
|
||||
cn.on('h265',function(d){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].mon||!s.group[d.ke].mon[d.id]){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].activeMonitors||!s.group[d.ke].activeMonitors[d.id]){
|
||||
cn.disconnect();return;
|
||||
}
|
||||
cn.ip=cn.request.connection.remoteAddress;
|
||||
|
@ -87,10 +66,10 @@ module.exports = function(s,config,lang,io){
|
|||
r=r[0];
|
||||
var Emitter,chunkChannel
|
||||
if(!d.channel){
|
||||
Emitter = s.group[d.ke].mon[d.id].emitter
|
||||
Emitter = s.group[d.ke].activeMonitors[d.id].emitter
|
||||
chunkChannel = 'MAIN'
|
||||
}else{
|
||||
Emitter = s.group[d.ke].mon[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
|
||||
Emitter = s.group[d.ke].activeMonitors[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
|
||||
chunkChannel = parseInt(d.channel)+config.pipeAddition
|
||||
}
|
||||
if(!Emitter){
|
||||
|
@ -144,7 +123,7 @@ module.exports = function(s,config,lang,io){
|
|||
})
|
||||
//unique Base64 socket stream
|
||||
cn.on('Base64',function(d){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].mon||!s.group[d.ke].mon[d.id]){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].activeMonitors||!s.group[d.ke].activeMonitors[d.id]){
|
||||
cn.disconnect();return;
|
||||
}
|
||||
cn.ip=cn.request.connection.remoteAddress;
|
||||
|
@ -160,10 +139,10 @@ module.exports = function(s,config,lang,io){
|
|||
r=r[0];
|
||||
var Emitter,chunkChannel
|
||||
if(!d.channel){
|
||||
Emitter = s.group[d.ke].mon[d.id].emitter
|
||||
Emitter = s.group[d.ke].activeMonitors[d.id].emitter
|
||||
chunkChannel = 'MAIN'
|
||||
}else{
|
||||
Emitter = s.group[d.ke].mon[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
|
||||
Emitter = s.group[d.ke].activeMonitors[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
|
||||
chunkChannel = parseInt(d.channel)+config.pipeAddition
|
||||
}
|
||||
if(!Emitter){
|
||||
|
@ -217,7 +196,7 @@ module.exports = function(s,config,lang,io){
|
|||
})
|
||||
//unique FLV socket stream
|
||||
cn.on('FLV',function(d){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].mon||!s.group[d.ke].mon[d.id]){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].activeMonitors||!s.group[d.ke].activeMonitors[d.id]){
|
||||
cn.disconnect();return;
|
||||
}
|
||||
cn.ip=cn.request.connection.remoteAddress;
|
||||
|
@ -233,10 +212,10 @@ module.exports = function(s,config,lang,io){
|
|||
r=r[0];
|
||||
var Emitter,chunkChannel
|
||||
if(!d.channel){
|
||||
Emitter = s.group[d.ke].mon[d.id].emitter
|
||||
Emitter = s.group[d.ke].activeMonitors[d.id].emitter
|
||||
chunkChannel = 'MAIN'
|
||||
}else{
|
||||
Emitter = s.group[d.ke].mon[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
|
||||
Emitter = s.group[d.ke].activeMonitors[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
|
||||
chunkChannel = parseInt(d.channel)+config.pipeAddition
|
||||
}
|
||||
if(!Emitter){
|
||||
|
@ -253,7 +232,7 @@ module.exports = function(s,config,lang,io){
|
|||
cn.closeSocketVideoStream = function(){
|
||||
Emitter.removeListener('data', contentWriter);
|
||||
}
|
||||
tx({time:toUTC(),buffer:s.group[d.ke].mon[d.id].firstStreamChunk[chunkChannel]})
|
||||
tx({time:toUTC(),buffer:s.group[d.ke].activeMonitors[d.id].firstStreamChunk[chunkChannel]})
|
||||
Emitter.on('data',contentWriter = function(buffer){
|
||||
tx({time:toUTC(),buffer:buffer})
|
||||
})
|
||||
|
@ -290,7 +269,7 @@ module.exports = function(s,config,lang,io){
|
|||
})
|
||||
//unique MP4 socket stream
|
||||
cn.on('MP4',function(d){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].mon||!s.group[d.ke].mon[d.id]){
|
||||
if(!s.group[d.ke]||!s.group[d.ke].activeMonitors||!s.group[d.ke].activeMonitors[d.id]){
|
||||
cn.disconnect();return;
|
||||
}
|
||||
cn.ip=cn.request.connection.remoteAddress;
|
||||
|
@ -306,10 +285,10 @@ module.exports = function(s,config,lang,io){
|
|||
r=r[0];
|
||||
var Emitter,chunkChannel
|
||||
if(!d.channel){
|
||||
Emitter = s.group[d.ke].mon[d.id].emitter
|
||||
Emitter = s.group[d.ke].activeMonitors[d.id].emitter
|
||||
chunkChannel = 'MAIN'
|
||||
}else{
|
||||
Emitter = s.group[d.ke].mon[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
|
||||
Emitter = s.group[d.ke].activeMonitors[d.id].emitterChannel[parseInt(d.channel)+config.pipeAddition]
|
||||
chunkChannel = parseInt(d.channel)+config.pipeAddition
|
||||
}
|
||||
if(!Emitter){
|
||||
|
@ -321,7 +300,7 @@ module.exports = function(s,config,lang,io){
|
|||
cn.auth=d.auth;
|
||||
cn.channel=d.channel;
|
||||
cn.socketVideoStream=d.id;
|
||||
var mp4frag = s.group[d.ke].mon[d.id].mp4frag[d.channel];
|
||||
var mp4frag = s.group[d.ke].activeMonitors[d.id].mp4frag[d.channel];
|
||||
var onInitialized = () => {
|
||||
cn.emit('mime', mp4frag.mime);
|
||||
mp4frag.removeListener('initialized', onInitialized);
|
||||
|
@ -438,13 +417,9 @@ module.exports = function(s,config,lang,io){
|
|||
}
|
||||
s.group[d.ke].users[d.auth].lang=s.getLanguageFile(s.group[d.ke].users[d.auth].details.lang)
|
||||
s.userLog({ke:d.ke,mid:'$USER'},{type:s.group[d.ke].users[d.auth].lang['Websocket Connected'],msg:{mail:r.mail,id:d.uid,ip:cn.ip}})
|
||||
if(!s.group[d.ke].mon){
|
||||
s.group[d.ke].mon={}
|
||||
if(!s.group[d.ke].mon){s.group[d.ke].mon={}}
|
||||
}
|
||||
if(s.isAtleatOneDetectorPluginConnected){
|
||||
s.sendDetectorInfoToClient({f:'detector_plugged'},tx)
|
||||
s.ocvTx({f:'readPlugins',ke:d.ke})
|
||||
if(!s.group[d.ke].activeMonitors){
|
||||
s.group[d.ke].activeMonitors={}
|
||||
if(!s.group[d.ke].activeMonitors){s.group[d.ke].activeMonitors={}}
|
||||
}
|
||||
tx({f:'users_online',users:s.group[d.ke].users})
|
||||
s.tx({f:'user_status_change',ke:d.ke,uid:cn.uid,status:1,user:s.group[d.ke].users[d.auth]},'GRP_'+d.ke)
|
||||
|
@ -465,7 +440,7 @@ module.exports = function(s,config,lang,io){
|
|||
s.sqlQuery('SELECT * FROM Monitors WHERE ke=?', [d.ke], function(err,r) {
|
||||
if(r && r[0]){
|
||||
r.forEach(function(monitor){
|
||||
s.cameraSendSnapshot({mid:monitor.mid,ke:monitor.ke,mon:monitor})
|
||||
s.cameraSendSnapshot({mid:monitor.mid,ke:monitor.ke,mon:monitor},{useIcon: true})
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -474,7 +449,7 @@ module.exports = function(s,config,lang,io){
|
|||
}
|
||||
})
|
||||
s.onSocketAuthenticationExtensions.forEach(function(extender){
|
||||
extender(r,cn)
|
||||
extender(r,cn,d,tx)
|
||||
})
|
||||
}
|
||||
s.sqlQuery('SELECT ke,uid,auth,mail,details FROM Users WHERE ke=? AND auth=? AND uid=?',[d.ke,d.auth,d.uid],function(err,r) {
|
||||
|
@ -507,9 +482,6 @@ module.exports = function(s,config,lang,io){
|
|||
if((d.id||d.uid||d.mid)&&cn.ke){
|
||||
try{
|
||||
switch(d.f){
|
||||
case'ocv_in':
|
||||
s.ocvTx(d.data)
|
||||
break;
|
||||
case'monitorOrder':
|
||||
if(d.monitorOrder && d.monitorOrder instanceof Object){
|
||||
s.sqlQuery('SELECT details FROM Users WHERE uid=? AND ke=?',[cn.uid,cn.ke],function(err,r){
|
||||
|
@ -744,9 +716,10 @@ module.exports = function(s,config,lang,io){
|
|||
getVideos(function(videos){
|
||||
getEvents(function(events){
|
||||
tx({
|
||||
f:'drawPowerVideoMainTimeLine',
|
||||
videos:videos,
|
||||
events:events
|
||||
f: 'videos&events',
|
||||
id: d.mid,
|
||||
videos: videos,
|
||||
events: events
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -781,7 +754,7 @@ module.exports = function(s,config,lang,io){
|
|||
case'watch_on':
|
||||
if(!d.ke){d.ke=cn.ke}
|
||||
s.initiateMonitorObject({mid:d.id,ke:d.ke});
|
||||
if(!s.group[d.ke]||!s.group[d.ke].mon[d.id]||s.group[d.ke].mon[d.id].isStarted === false){return false}
|
||||
if(!s.group[d.ke]||!s.group[d.ke].activeMonitors[d.id]||s.group[d.ke].activeMonitors[d.id].isStarted === false){return false}
|
||||
cn.join('MON_'+d.ke+d.id);
|
||||
cn.join('DETECTOR_'+d.ke+d.id);
|
||||
if(cn.jpeg_on !== true){
|
||||
|
@ -951,6 +924,7 @@ module.exports = function(s,config,lang,io){
|
|||
var tempSessionKey = s.gid(30)
|
||||
cn.superSessionKey = tempSessionKey
|
||||
s.superUsersApi[tempSessionKey] = data
|
||||
s.superUsersApi[tempSessionKey].cnid = cn.id
|
||||
if(!data.$user.tokens)data.$user.tokens = {}
|
||||
data.$user.tokens[tempSessionKey] = {}
|
||||
cn.ip=cn.request.connection.remoteAddress
|
||||
|
@ -1229,15 +1203,15 @@ module.exports = function(s,config,lang,io){
|
|||
login_type:'Streamer'
|
||||
}
|
||||
s.group[d.ke].dashcamUsers[d.auth] = s.group[d.ke].users[d.auth]
|
||||
if(s.group[d.ke].mon){
|
||||
Object.keys(s.group[d.ke].mon).forEach(function(monitorId){
|
||||
if(s.group[d.ke].activeMonitors){
|
||||
Object.keys(s.group[d.ke].activeMonitors).forEach(function(monitorId){
|
||||
var dataToClient = {
|
||||
f : 'disable_stream',
|
||||
mid : monitorId,
|
||||
ke : d.ke
|
||||
}
|
||||
var mon = s.group[d.ke].mon[monitorId]
|
||||
if(s.group[d.ke].mon_conf[monitorId].type === 'dashcam'){
|
||||
var mon = s.group[d.ke].activeMonitors[monitorId]
|
||||
if(s.group[d.ke].rawMonitorConfigurations[monitorId].type === 'dashcam'){
|
||||
if(mon.allowStdinWrite === true){
|
||||
dataToClient.f = 'enable_stream'
|
||||
}
|
||||
|
@ -1248,22 +1222,22 @@ module.exports = function(s,config,lang,io){
|
|||
}
|
||||
})
|
||||
}else{
|
||||
if(s.group[d.ke] && s.group[d.ke].mon[d.mid]){
|
||||
if(s.group[d.ke].mon[d.mid].allowStdinWrite === true){
|
||||
if(s.group[d.ke] && s.group[d.ke].activeMonitors[d.mid]){
|
||||
if(s.group[d.ke].activeMonitors[d.mid].allowStdinWrite === true){
|
||||
switch(d.f){
|
||||
case'monitor_chunk':
|
||||
if(s.group[d.ke].mon[d.mid].isStarted !== true || !s.group[d.ke].mon[d.mid].spawn || !s.group[d.ke].mon[d.mid].spawn.stdin){
|
||||
if(s.group[d.ke].activeMonitors[d.mid].isStarted !== true || !s.group[d.ke].activeMonitors[d.mid].spawn || !s.group[d.ke].activeMonitors[d.mid].spawn.stdin){
|
||||
s.tx({error:'Not Started'},cn.id);
|
||||
return false
|
||||
};
|
||||
s.group[d.ke].mon[d.mid].spawn.stdin.write(new Buffer(d.chunk, "binary"));
|
||||
s.group[d.ke].activeMonitors[d.mid].spawn.stdin.write(new Buffer(d.chunk, "binary"));
|
||||
break;
|
||||
case'monitor_frame':
|
||||
if(s.group[d.ke].mon[d.mid].isStarted !== true){
|
||||
if(s.group[d.ke].activeMonitors[d.mid].isStarted !== true){
|
||||
s.tx({error:'Not Started'},cn.id);
|
||||
return false
|
||||
};
|
||||
s.group[d.ke].mon[d.mid].spawn.stdin.write(d.frame);
|
||||
s.group[d.ke].activeMonitors[d.mid].spawn.stdin.write(d.frame);
|
||||
break;
|
||||
}
|
||||
}else{
|
||||
|
@ -1279,7 +1253,7 @@ module.exports = function(s,config,lang,io){
|
|||
tx=function(z){if(!z.ke){z.ke=cn.ke;};cn.emit('f',z);}
|
||||
switch(d.f){
|
||||
case'init':
|
||||
if(!s.group[d.ke]||!s.group[d.ke].mon[d.id]||s.group[d.ke].mon[d.id].isStarted === false){return false}
|
||||
if(!s.group[d.ke]||!s.group[d.ke].activeMonitors[d.id]||s.group[d.ke].activeMonitors[d.id].isStarted === false){return false}
|
||||
s.auth({auth:d.auth,ke:d.ke,id:d.id,ip:cn.request.connection.remoteAddress},function(user){
|
||||
cn.embedded=1;
|
||||
cn.ke=d.ke;
|
||||
|
@ -1294,10 +1268,10 @@ module.exports = function(s,config,lang,io){
|
|||
cn.join('MON_STREAM_'+d.ke+d.id);
|
||||
cn.join('DETECTOR_'+d.ke+d.id);
|
||||
cn.join('STR_'+d.ke);
|
||||
if(s.group[d.ke]&&s.group[d.ke].mon[d.id]&&s.group[d.ke].mon[d.id].watch){
|
||||
if(s.group[d.ke]&&s.group[d.ke].activeMonitors[d.id]&&s.group[d.ke].activeMonitors[d.id].watch){
|
||||
|
||||
tx({f:'monitor_watch_on',id:d.id,ke:d.ke},'MON_'+d.ke+d.id)
|
||||
s.tx({viewers:Object.keys(s.group[d.ke].mon[d.id].watch).length,ke:d.ke,id:d.id},'MON_'+d.ke+d.id)
|
||||
s.tx({viewers:Object.keys(s.group[d.ke].activeMonitors[d.id].watch).length,ke:d.ke,id:d.id},'MON_'+d.ke+d.id)
|
||||
}
|
||||
});
|
||||
break;
|
||||
|
@ -1364,20 +1338,9 @@ module.exports = function(s,config,lang,io){
|
|||
if(s.group[cn.ke].dashcamUsers && s.group[cn.ke].dashcamUsers[cn.auth])delete(s.group[cn.ke].dashcamUsers[cn.auth]);
|
||||
}
|
||||
}
|
||||
if(cn.pluginEngine){
|
||||
s.connectedPlugins[cn.pluginEngine].plugged = false
|
||||
s.tx({f:'plugin_engine_unplugged',plug:cn.pluginEngine},'CPU')
|
||||
}
|
||||
if(cn.cron){
|
||||
delete(s.cron);
|
||||
}
|
||||
if(cn.detectorPlugin){
|
||||
s.tx({f:'detector_unplugged',plug:cn.detectorPlugin},'CPU')
|
||||
s.removeDetectorPlugin(cn.detectorPlugin)
|
||||
s.sendDetectorInfoToClient({f:'detector_plugged'},function(data){
|
||||
s.tx(data,'CPU')
|
||||
})
|
||||
}
|
||||
if(cn.superSessionKey){
|
||||
delete(s.superUsersApi[cn.superSessionKey])
|
||||
}
|
||||
|
|
30
libs/sql.js
30
libs/sql.js
|
@ -1,3 +1,5 @@
|
|||
var fs = require('fs');
|
||||
var async = require("async");
|
||||
module.exports = function(s,config){
|
||||
s.onBeforeDatabaseLoadExtensions.forEach(function(extender){
|
||||
extender(config)
|
||||
|
@ -8,8 +10,8 @@ module.exports = function(s,config){
|
|||
connection: config.db,
|
||||
}
|
||||
if(s.databaseOptions.client.indexOf('sqlite')>-1){
|
||||
s.databaseOptions.client = 'sqlite3';
|
||||
s.databaseOptions.useNullAsDefault = true;
|
||||
s.databaseOptions.client = 'sqlite3'
|
||||
s.databaseOptions.useNullAsDefault = true
|
||||
try{
|
||||
require('sqlite3')
|
||||
}catch(err){
|
||||
|
@ -54,6 +56,11 @@ module.exports = function(s,config){
|
|||
newValue = new Date(value.replace('T',' '))
|
||||
return newValue
|
||||
}
|
||||
var runQuery = async.queue(function(data, callback) {
|
||||
s.databaseEngine
|
||||
.raw(data.query,data.values)
|
||||
.asCallback(callback)
|
||||
}, 4);
|
||||
s.sqlQuery = function(query,values,onMoveOn,hideLog){
|
||||
if(!values){values=[]}
|
||||
if(typeof values === 'function'){
|
||||
|
@ -66,14 +73,17 @@ module.exports = function(s,config){
|
|||
// .replace(/ NOT LIKE /g," NOT ILIKE ")
|
||||
// .replace(/ LIKE /g," ILIKE ")
|
||||
// }
|
||||
var mergedQuery = s.mergeQueryValues(query,values)
|
||||
s.debugLog('s.sqlQuery QUERY',mergedQuery)
|
||||
if(config.debugLog === true){
|
||||
var mergedQuery = s.mergeQueryValues(query,values)
|
||||
s.debugLog('s.sqlQuery QUERY',mergedQuery)
|
||||
}
|
||||
if(!s.databaseEngine || !s.databaseEngine.raw){
|
||||
s.connectDatabase()
|
||||
}
|
||||
return s.databaseEngine
|
||||
.raw(query,values)
|
||||
.asCallback(function(err,r){
|
||||
return runQuery.push({
|
||||
query: query,
|
||||
values: values
|
||||
},function(err,r){
|
||||
if(err && !hideLog){
|
||||
console.log('s.sqlQuery QUERY ERRORED',query)
|
||||
console.log('s.sqlQuery ERROR',err)
|
||||
|
@ -129,6 +139,10 @@ module.exports = function(s,config){
|
|||
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Cloud Videos` (`mid` varchar(50) NOT NULL,`ke` varchar(50) DEFAULT NULL,`href` text NOT NULL,`size` float DEFAULT NULL,`time` timestamp NULL DEFAULT NULL,`end` timestamp NULL DEFAULT NULL,`status` int(1) DEFAULT \'0\',`details` text)' + mySQLtail + ';',[],function(err){
|
||||
if(err)console.error(err)
|
||||
},true)
|
||||
//add Cloud Timelapse Frames table, will remove in future
|
||||
s.sqlQuery('CREATE TABLE IF NOT EXISTS `Cloud Timelapse Frames` (`ke` varchar(50) NOT NULL,`mid` varchar(50) NOT NULL,`href` text NOT NULL,`details` longtext,`filename` varchar(50) NOT NULL,`time` timestamp NULL DEFAULT NULL,`size` int(11) NOT NULL)' + mySQLtail + ';',[],function(err){
|
||||
if(err)console.error(err)
|
||||
},true)
|
||||
//create Files table
|
||||
var createFilesTableQuery = "CREATE TABLE IF NOT EXISTS `Files` (`ke` varchar(50) NOT NULL,`mid` varchar(50) NOT NULL,`name` tinytext NOT NULL,`size` float NOT NULL DEFAULT '0',`details` text NOT NULL,`status` int(1) NOT NULL DEFAULT '0',`time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP)"
|
||||
s.sqlQuery(createFilesTableQuery + mySQLtail + ';',[],function(err){
|
||||
|
@ -140,7 +154,7 @@ module.exports = function(s,config){
|
|||
aQuery += "INSERT INTO Files (`ke`, `mid`, `name`, `details`, `size`, `status`, `time`) SELECT `ke`, `mid`, `name`, `details`, `size`, `status`, `time` FROM _Files_old;COMMIT;DROP TABLE _Files_old;"
|
||||
}else{
|
||||
s.sqlQuery('ALTER TABLE `Files` ADD COLUMN `time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;',[],function(err){
|
||||
if(err && err.sqlMessage.indexOf('Duplicate') === -1)console.error(err)
|
||||
if(err && err.sqlMessage && err.sqlMessage.indexOf('Duplicate') === -1)console.error(err)
|
||||
},true)
|
||||
}
|
||||
},true)
|
||||
|
|
300
libs/startup.js
300
libs/startup.js
|
@ -1,12 +1,13 @@
|
|||
|
||||
var fs = require('fs');
|
||||
var request = require('request');
|
||||
var moment = require('moment');
|
||||
var crypto = require('crypto');
|
||||
var exec = require('child_process').exec;
|
||||
var execSync = require('child_process').execSync;
|
||||
module.exports = function(s,config,lang,io){
|
||||
console.log('FFmpeg version : '+s.ffmpegVersion)
|
||||
console.log('Node.js version : '+execSync("node -v"))
|
||||
console.log('Node.js version : '+process.version)
|
||||
s.processReady = function(){
|
||||
s.systemLog(lang.startUpText5)
|
||||
s.onProcessReadyExtensions.forEach(function(extender){
|
||||
|
@ -18,7 +19,7 @@ module.exports = function(s,config,lang,io){
|
|||
var next = function(){
|
||||
if(callback)callback()
|
||||
}
|
||||
if(!s.isWin){
|
||||
if(!s.isWin && s.packageJson.mainDirectory !== '.'){
|
||||
var etcPath = '/etc/shinobisystems/cctv.txt'
|
||||
fs.stat(etcPath,function(err,stat){
|
||||
if(err || !stat){
|
||||
|
@ -33,6 +34,7 @@ module.exports = function(s,config,lang,io){
|
|||
}
|
||||
}
|
||||
var loadedAccounts = []
|
||||
var foundMonitors = []
|
||||
var loadMonitors = function(callback){
|
||||
s.beforeMonitorsLoadedOnStartupExtensions.forEach(function(extender){
|
||||
extender()
|
||||
|
@ -40,19 +42,17 @@ module.exports = function(s,config,lang,io){
|
|||
s.systemLog(lang.startUpText4)
|
||||
//preliminary monitor start
|
||||
s.sqlQuery('SELECT * FROM Monitors', function(err,monitors) {
|
||||
foundMonitors = monitors
|
||||
if(err){s.systemLog(err)}
|
||||
if(monitors && monitors[0]){
|
||||
var loadCompleted = 0
|
||||
var orphanedVideosForMonitors = {}
|
||||
var loadMonitor = function(monitor){
|
||||
if(!orphanedVideosForMonitors[monitor.ke])orphanedVideosForMonitors[monitor.ke] = {}
|
||||
if(!orphanedVideosForMonitors[monitor.ke][monitor.mid])orphanedVideosForMonitors[monitor.ke][monitor.mid] = 0
|
||||
s.initiateMonitorObject(monitor)
|
||||
s.orphanedVideoCheck(monitor,2,function(orphanedFilesCount){
|
||||
if(orphanedFilesCount){
|
||||
orphanedVideosForMonitors[monitor.ke][monitor.mid] += orphanedFilesCount
|
||||
}
|
||||
s.group[monitor.ke].mon_conf[monitor.mid] = monitor
|
||||
setTimeout(function(){
|
||||
if(!orphanedVideosForMonitors[monitor.ke])orphanedVideosForMonitors[monitor.ke] = {}
|
||||
if(!orphanedVideosForMonitors[monitor.ke][monitor.mid])orphanedVideosForMonitors[monitor.ke][monitor.mid] = 0
|
||||
s.initiateMonitorObject(monitor)
|
||||
s.group[monitor.ke].rawMonitorConfigurations[monitor.mid] = monitor
|
||||
s.sendMonitorStatus({id:monitor.mid,ke:monitor.ke,status:'Stopped'});
|
||||
var monObj = Object.assign(monitor,{id : monitor.mid})
|
||||
s.camera(monitor.mode,monObj)
|
||||
|
@ -60,10 +60,9 @@ module.exports = function(s,config,lang,io){
|
|||
if(monitors[loadCompleted]){
|
||||
loadMonitor(monitors[loadCompleted])
|
||||
}else{
|
||||
s.systemLog(lang.startUpText6+' : '+s.s(orphanedVideosForMonitors))
|
||||
callback()
|
||||
}
|
||||
})
|
||||
},2000)
|
||||
}
|
||||
loadMonitor(monitors[loadCompleted])
|
||||
}else{
|
||||
|
@ -71,19 +70,89 @@ module.exports = function(s,config,lang,io){
|
|||
}
|
||||
})
|
||||
}
|
||||
var checkForOrphanedVideos = function(callback){
|
||||
var monitors = foundMonitors
|
||||
if(monitors && monitors[0]){
|
||||
var loadCompleted = 0
|
||||
var orphanedVideosForMonitors = {}
|
||||
var checkForOrphanedVideosForMonitor = function(monitor){
|
||||
if(!orphanedVideosForMonitors[monitor.ke])orphanedVideosForMonitors[monitor.ke] = {}
|
||||
if(!orphanedVideosForMonitors[monitor.ke][monitor.mid])orphanedVideosForMonitors[monitor.ke][monitor.mid] = 0
|
||||
s.orphanedVideoCheck(monitor,null,function(orphanedFilesCount){
|
||||
if(orphanedFilesCount){
|
||||
orphanedVideosForMonitors[monitor.ke][monitor.mid] += orphanedFilesCount
|
||||
}
|
||||
++loadCompleted
|
||||
if(monitors[loadCompleted]){
|
||||
checkForOrphanedVideosForMonitor(monitors[loadCompleted])
|
||||
}else{
|
||||
s.systemLog(lang.startUpText6+' : '+s.s(orphanedVideosForMonitors))
|
||||
delete(foundMonitors)
|
||||
callback()
|
||||
}
|
||||
})
|
||||
}
|
||||
checkForOrphanedVideosForMonitor(monitors[loadCompleted])
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
}
|
||||
var loadDiskUseForUser = function(user,callback){
|
||||
s.systemLog(user.mail+' : '+lang.startUpText0)
|
||||
var userDetails = JSON.parse(user.details)
|
||||
user.size = 0
|
||||
user.limit = userDetails.size
|
||||
s.group[user.ke].sizeLimit = parseFloat(userDetails.size) || 10000
|
||||
s.group[user.ke].sizeLimitVideoPercent = parseFloat(userDetails.size_video_percent) || 90
|
||||
s.group[user.ke].sizeLimitTimelapseFramesPercent = parseFloat(userDetails.size_timelapse_percent) || 10
|
||||
s.sqlQuery('SELECT * FROM Videos WHERE ke=? AND status!=?',[user.ke,0],function(err,videos){
|
||||
if(videos && videos[0]){
|
||||
videos.forEach(function(video){
|
||||
user.size += video.size
|
||||
s.sqlQuery('SELECT * FROM `Timelapse Frames` WHERE ke=?',[user.ke],function(err,timelapseFrames){
|
||||
s.sqlQuery('SELECT * FROM `Files` WHERE ke=?',[user.ke],function(err,files){
|
||||
var usedSpaceVideos = 0
|
||||
var usedSpaceTimelapseFrames = 0
|
||||
var usedSpaceFilebin = 0
|
||||
var addStorageData = {
|
||||
files: [],
|
||||
videos: [],
|
||||
timelapeFrames: [],
|
||||
}
|
||||
if(videos && videos[0]){
|
||||
videos.forEach(function(video){
|
||||
video.details = s.parseJSON(video.details)
|
||||
if(!video.details.dir){
|
||||
usedSpaceVideos += video.size
|
||||
}else{
|
||||
addStorageData.videos.push(video)
|
||||
}
|
||||
})
|
||||
}
|
||||
if(timelapseFrames && timelapseFrames[0]){
|
||||
timelapseFrames.forEach(function(frame){
|
||||
frame.details = s.parseJSON(frame.details)
|
||||
if(!frame.details.dir){
|
||||
usedSpaceTimelapseFrames += frame.size
|
||||
}else{
|
||||
addStorageData.timelapeFrames.push(frame)
|
||||
}
|
||||
})
|
||||
}
|
||||
if(files && files[0]){
|
||||
files.forEach(function(file){
|
||||
file.details = s.parseJSON(file.details)
|
||||
if(!file.details.dir){
|
||||
usedSpaceFilebin += file.size
|
||||
}else{
|
||||
addStorageData.files.push(file)
|
||||
}
|
||||
})
|
||||
}
|
||||
s.group[user.ke].usedSpace = (usedSpaceVideos + usedSpaceTimelapseFrames + usedSpaceFilebin) / 1000000
|
||||
s.group[user.ke].usedSpaceVideos = usedSpaceVideos / 1000000
|
||||
s.group[user.ke].usedSpaceFilebin = usedSpaceFilebin / 1000000
|
||||
s.group[user.ke].usedSpaceTimelapseFrames = usedSpaceTimelapseFrames / 1000000
|
||||
loadAddStorageDiskUseForUser(user,addStorageData,function(){
|
||||
callback()
|
||||
})
|
||||
})
|
||||
}
|
||||
s.systemLog(user.mail+' : '+lang.startUpText1+' : '+videos.length,user.size)
|
||||
callback()
|
||||
})
|
||||
})
|
||||
}
|
||||
var loadCloudDiskUseForUser = function(user,callback){
|
||||
|
@ -98,23 +167,108 @@ module.exports = function(s,config,lang,io){
|
|||
}
|
||||
if(s.cloudDiskUseStartupExtensions[storageType])s.cloudDiskUseStartupExtensions[storageType](user,userDetails)
|
||||
})
|
||||
s.sqlQuery('SELECT * FROM `Cloud Videos` WHERE ke=? AND status!=?',[user.ke,0],function(err,videos){
|
||||
var loadCloudVideos = function(callback){
|
||||
s.sqlQuery('SELECT * FROM `Cloud Videos` WHERE ke=? AND status!=?',[user.ke,0],function(err,videos){
|
||||
if(videos && videos[0]){
|
||||
videos.forEach(function(video){
|
||||
var storageType = JSON.parse(video.details).type
|
||||
if(!storageType)storageType = 's3'
|
||||
var videoSize = video.size / 1000000
|
||||
user.cloudDiskUse[storageType].usedSpace += videoSize
|
||||
user.cloudDiskUse[storageType].usedSpaceVideos += videoSize
|
||||
++user.cloudDiskUse[storageType].firstCount
|
||||
})
|
||||
s.cloudDisksLoaded.forEach(function(storageType){
|
||||
var firstCount = user.cloudDiskUse[storageType].firstCount
|
||||
s.systemLog(user.mail+' : '+lang.startUpText1+' : '+firstCount,storageType,user.cloudDiskUse[storageType].usedSpace)
|
||||
delete(user.cloudDiskUse[storageType].firstCount)
|
||||
})
|
||||
}
|
||||
callback()
|
||||
})
|
||||
}
|
||||
var loadCloudTimelapseFrames = function(callback){
|
||||
s.sqlQuery('SELECT * FROM `Cloud Timelapse Frames` WHERE ke=?',[user.ke],function(err,frames){
|
||||
if(frames && frames[0]){
|
||||
frames.forEach(function(frame){
|
||||
var storageType = JSON.parse(frame.details).type
|
||||
if(!storageType)storageType = 's3'
|
||||
var frameSize = frame.size / 1000000
|
||||
user.cloudDiskUse[storageType].usedSpace += frameSize
|
||||
user.cloudDiskUse[storageType].usedSpaceTimelapseFrames += frameSize
|
||||
})
|
||||
}
|
||||
callback()
|
||||
})
|
||||
}
|
||||
loadCloudVideos(function(){
|
||||
loadCloudTimelapseFrames(function(){
|
||||
s.group[user.ke].cloudDiskUse = user.cloudDiskUse
|
||||
callback()
|
||||
})
|
||||
})
|
||||
}
|
||||
var loadAddStorageDiskUseForUser = function(user,data,callback){
|
||||
var videos = data.videos
|
||||
var timelapseFrames = data.timelapseFrames
|
||||
var files = data.files
|
||||
var userDetails = JSON.parse(user.details)
|
||||
var userAddStorageData = s.parseJSON(userDetails.addStorage) || {}
|
||||
var currentStorageNumber = 0
|
||||
var readStorageArray = function(){
|
||||
var storage = s.listOfStorage[currentStorageNumber]
|
||||
if(!storage){
|
||||
//done all checks, move on to next user
|
||||
callback()
|
||||
return
|
||||
}
|
||||
var path = storage.value
|
||||
if(path === ''){
|
||||
++currentStorageNumber
|
||||
readStorageArray()
|
||||
return
|
||||
}
|
||||
var storageId = path
|
||||
var storageData = userAddStorageData[storageId] || {}
|
||||
if(!s.group[user.ke].addStorageUse[storageId])s.group[user.ke].addStorageUse[storageId] = {}
|
||||
var storageIndex = s.group[user.ke].addStorageUse[storageId]
|
||||
storageIndex.name = storage.name
|
||||
storageIndex.path = path
|
||||
storageIndex.usedSpace = 0
|
||||
storageIndex.sizeLimit = parseFloat(storageData.limit) || parseFloat(userDetails.size) || 10000
|
||||
var usedSpaceVideos = 0
|
||||
var usedSpaceTimelapseFrames = 0
|
||||
var usedSpaceFilebin = 0
|
||||
if(videos && videos[0]){
|
||||
videos.forEach(function(video){
|
||||
var storageType = JSON.parse(video.details).type
|
||||
if(!storageType)storageType = 's3'
|
||||
user.cloudDiskUse[storageType].usedSpace += (video.size /1000000)
|
||||
++user.cloudDiskUse[storageType].firstCount
|
||||
})
|
||||
s.cloudDisksLoaded.forEach(function(storageType){
|
||||
var firstCount = user.cloudDiskUse[storageType].firstCount
|
||||
s.systemLog(user.mail+' : '+lang.startUpText1+' : '+firstCount,storageType,user.cloudDiskUse[storageType].usedSpace)
|
||||
delete(user.cloudDiskUse[storageType].firstCount)
|
||||
if(video.details.dir === storage.value){
|
||||
usedSpaceVideos += video.size
|
||||
}
|
||||
})
|
||||
}
|
||||
s.group[user.ke].cloudDiskUse = user.cloudDiskUse
|
||||
callback()
|
||||
})
|
||||
if(timelapseFrames && timelapseFrames[0]){
|
||||
timelapseFrames.forEach(function(frame){
|
||||
if(video.details.dir === storage.value){
|
||||
usedSpaceTimelapseFrames += frame.size
|
||||
}
|
||||
})
|
||||
}
|
||||
if(files && files[0]){
|
||||
files.forEach(function(file){
|
||||
if(video.details.dir === storage.value){
|
||||
usedSpaceFilebin += file.size
|
||||
}
|
||||
})
|
||||
}
|
||||
storageIndex.usedSpace = (usedSpaceVideos + usedSpaceTimelapseFrames + usedSpaceFilebin) / 1000000
|
||||
storageIndex.usedSpaceVideos = usedSpaceVideos / 1000000
|
||||
storageIndex.usedSpaceFilebin = usedSpaceFilebin / 1000000
|
||||
storageIndex.usedSpaceTimelapseFrames = usedSpaceTimelapseFrames / 1000000
|
||||
s.systemLog(user.mail+' : '+path+' : '+videos.length,storageIndex.usedSpace)
|
||||
++currentStorageNumber
|
||||
readStorageArray()
|
||||
}
|
||||
readStorageArray()
|
||||
}
|
||||
var loadAdminUsers = function(callback){
|
||||
//get current disk used for each isolated account (admin user) on startup
|
||||
|
@ -124,10 +278,10 @@ module.exports = function(s,config,lang,io){
|
|||
var count = users.length
|
||||
var countFinished = 0
|
||||
users.forEach(function(user){
|
||||
s.loadGroup(user)
|
||||
s.loadGroupApps(user)
|
||||
loadedAccounts.push(user.ke)
|
||||
loadDiskUseForUser(user,function(){
|
||||
s.loadGroup(user)
|
||||
s.loadGroupApps(user)
|
||||
++countFinished
|
||||
if(countFinished === count){
|
||||
callback()
|
||||
|
@ -157,36 +311,76 @@ module.exports = function(s,config,lang,io){
|
|||
}
|
||||
})
|
||||
}
|
||||
config.userHasSubscribed = false
|
||||
var checkSubscription = function(callback){
|
||||
var subscriptionFailed = function(){
|
||||
console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
||||
console.error('This Install of Shinobi is NOT Activated')
|
||||
console.error('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
||||
console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
||||
s.systemLog('This Install of Shinobi is NOT Activated')
|
||||
console.log('!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!')
|
||||
console.log('https://licenses.shinobi.video/subscribe')
|
||||
}
|
||||
if(config.subscriptionId){
|
||||
var url = 'https://licenses.shinobi.video/subscribe/check?subscriptionId=' + config.subscriptionId
|
||||
request(url,{
|
||||
method: 'GET',
|
||||
timeout: 30000
|
||||
}, function(err,resp,body){
|
||||
var json = s.parseJSON(body)
|
||||
if(err)console.log(err,json)
|
||||
var hasSubcribed = !!json.ok
|
||||
config.userHasSubscribed = hasSubcribed
|
||||
callback(hasSubcribed)
|
||||
if(config.userHasSubscribed){
|
||||
s.systemLog('This Install of Shinobi is Activated')
|
||||
}else{
|
||||
subscriptionFailed()
|
||||
}
|
||||
})
|
||||
}else{
|
||||
subscriptionFailed()
|
||||
callback(false)
|
||||
}
|
||||
}
|
||||
//check disk space every 20 minutes
|
||||
if(config.autoDropCache===true){
|
||||
setInterval(function(){
|
||||
exec('echo 3 > /proc/sys/vm/drop_caches',{detached: true})
|
||||
},60000*20)
|
||||
}
|
||||
//master node - startup functions
|
||||
setInterval(function(){
|
||||
s.cpuUsage(function(cpu){
|
||||
s.ramUsage(function(ram){
|
||||
s.tx({f:'os',cpu:cpu,ram:ram},'CPU');
|
||||
})
|
||||
})
|
||||
},10000)
|
||||
//hourly check to see if sizePurge has failed to unlock
|
||||
//checks to see if request count is the number of monitors + 10
|
||||
s.checkForStalePurgeLocks()
|
||||
//run prerequsite queries, load users and monitors
|
||||
if(config.childNodes.mode !== 'child'){
|
||||
//master node - startup functions
|
||||
setInterval(function(){
|
||||
s.cpuUsage(function(cpu){
|
||||
s.ramUsage(function(ram){
|
||||
s.tx({f:'os',cpu:cpu,ram:ram},'CPU');
|
||||
})
|
||||
})
|
||||
},10000)
|
||||
//hourly check to see if sizePurge has failed to unlock
|
||||
//checks to see if request count is the number of monitors + 10
|
||||
s.checkForStalePurgeLocks()
|
||||
//run prerequsite queries, load users and monitors
|
||||
//sql/database connection with knex
|
||||
s.databaseEngine = require('knex')(s.databaseOptions)
|
||||
//run prerequsite queries
|
||||
s.preQueries()
|
||||
setTimeout(function(){
|
||||
checkForTerminalCommands(function(){
|
||||
//load administrators (groups)
|
||||
loadAdminUsers(function(){
|
||||
//load monitors (for groups)
|
||||
loadMonitors(function(){
|
||||
s.processReady()
|
||||
//check for subscription
|
||||
checkSubscription(function(){
|
||||
//check terminal commander
|
||||
checkForTerminalCommands(function(){
|
||||
//load administrators (groups)
|
||||
loadAdminUsers(function(){
|
||||
//load monitors (for groups)
|
||||
loadMonitors(function(){
|
||||
//check for orphaned videos
|
||||
checkForOrphanedVideos(function(){
|
||||
s.processReady()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
368
libs/timelapse.js
Normal file
368
libs/timelapse.js
Normal file
|
@ -0,0 +1,368 @@
|
|||
var fs = require('fs')
|
||||
var moment = require('moment')
|
||||
var express = require('express')
|
||||
module.exports = function(s,config,lang,app,io){
|
||||
s.getTimelapseFrameDirectory = function(e){
|
||||
if(e.mid&&!e.id){e.id=e.mid}
|
||||
s.checkDetails(e)
|
||||
if(e.details&&e.details.dir&&e.details.dir!==''){
|
||||
return s.checkCorrectPathEnding(e.details.dir)+e.ke+'/'+e.id+'_timelapse/'
|
||||
}else{
|
||||
return s.dir.videos+e.ke+'/'+e.id+'_timelapse/';
|
||||
}
|
||||
}
|
||||
s.createTimelapseFrameAndInsert = function(e,location,filename){
|
||||
//e = monitor object
|
||||
//location = file location
|
||||
var filePath = location + filename
|
||||
var fileStats = fs.statSync(filePath)
|
||||
var details = {}
|
||||
if(e.details && e.details.dir && e.details.dir !== ''){
|
||||
details.dir = e.details.dir
|
||||
}
|
||||
var timeNow = new Date()
|
||||
var queryInfo = {
|
||||
ke: e.ke,
|
||||
mid: e.id,
|
||||
details: s.s(details),
|
||||
filename: filename,
|
||||
size: fileStats.size,
|
||||
time: timeNow
|
||||
}
|
||||
if(config.childNodes.enabled === true && config.childNodes.mode === 'child' && config.childNodes.host){
|
||||
var currentDate = s.formattedTime(queryInfo.time,'YYYY-MM-DD')
|
||||
s.cx({
|
||||
f: 'open_timelapse_file_transfer',
|
||||
ke: e.ke,
|
||||
mid: e.id,
|
||||
d: s.group[e.ke].rawMonitorConfigurations[e.id],
|
||||
filename: filename,
|
||||
currentDate: currentDate,
|
||||
queryInfo: queryInfo
|
||||
})
|
||||
var formattedTime = s.timeObject(timeNow).format()
|
||||
fs.createReadStream(filePath,{ highWaterMark: 500 })
|
||||
.on('data',function(data){
|
||||
s.cx({
|
||||
f: 'created_timelapse_file_chunk',
|
||||
ke: e.ke,
|
||||
mid: e.id,
|
||||
time: formattedTime,
|
||||
filesize: e.filesize,
|
||||
chunk: data,
|
||||
d: s.group[e.ke].rawMonitorConfigurations[e.id],
|
||||
filename: filename,
|
||||
currentDate: currentDate,
|
||||
queryInfo: queryInfo
|
||||
})
|
||||
})
|
||||
.on('close',function(){
|
||||
s.cx({
|
||||
f: 'created_timelapse_file',
|
||||
ke: e.ke,
|
||||
mid: e.id,
|
||||
time: formattedTime,
|
||||
filesize: e.filesize,
|
||||
d: s.group[e.ke].rawMonitorConfigurations[e.id],
|
||||
filename: filename,
|
||||
currentDate: currentDate,
|
||||
queryInfo: queryInfo
|
||||
})
|
||||
})
|
||||
}else{
|
||||
s.insertTimelapseFrameDatabaseRow(e,queryInfo,filePath)
|
||||
}
|
||||
}
|
||||
s.insertTimelapseFrameDatabaseRow = function(e,queryInfo,filePath){
|
||||
s.sqlQuery('INSERT INTO `Timelapse Frames` ('+Object.keys(queryInfo).join(',')+') VALUES (?,?,?,?,?,?)',Object.values(queryInfo))
|
||||
s.setDiskUsedForGroup(e,queryInfo.size / 1000000,'timelapeFrames')
|
||||
s.purgeDiskForGroup(e)
|
||||
s.onInsertTimelapseFrameExtensions.forEach(function(extender){
|
||||
extender(e,queryInfo,filePath)
|
||||
})
|
||||
}
|
||||
s.onDeleteTimelapseFrameFromCloudExtensions = {}
|
||||
s.onDeleteTimelapseFrameFromCloudExtensionsRunner = function(e,storageType,video){
|
||||
// e = user
|
||||
if(!storageType){
|
||||
var videoDetails = JSON.parse(r.details)
|
||||
videoDetails.type = videoDetails.type || 's3'
|
||||
}
|
||||
if(s.onDeleteTimelapseFrameFromCloudExtensions[storageType]){
|
||||
s.onDeleteTimelapseFrameFromCloudExtensions[storageType](e,video,function(){
|
||||
s.tx({
|
||||
f: 'timelapse_frame_delete_cloud',
|
||||
mid: e.mid,
|
||||
ke: e.ke,
|
||||
time: e.time,
|
||||
end: e.end
|
||||
},'GRP_'+e.ke);
|
||||
})
|
||||
}
|
||||
}
|
||||
s.deleteTimelapseFrameFromCloud = function(e){
|
||||
// e = video object
|
||||
s.checkDetails(e)
|
||||
var frameSelector = [e.id,e.ke,new Date(e.time)]
|
||||
s.sqlQuery('SELECT * FROM `Cloud Timelapse Frames` WHERE `mid`=? AND `ke`=? AND `time`=?',frameSelector,function(err,r){
|
||||
if(r&&r[0]){
|
||||
r = r[0]
|
||||
s.sqlQuery('DELETE FROM `Cloud Timelapse Frames` WHERE `mid`=? AND `ke`=? AND `time`=?',frameSelector,function(){
|
||||
s.onDeleteTimelapseFrameFromCloudExtensionsRunner(e,r)
|
||||
})
|
||||
}else{
|
||||
// console.log('Delete Failed',e)
|
||||
// console.error(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
// Web Paths
|
||||
// // // // //
|
||||
/**
|
||||
* API : Get Timelapse images
|
||||
*/
|
||||
app.get([
|
||||
config.webPaths.apiPrefix+':auth/timelapse/:ke',
|
||||
config.webPaths.apiPrefix+':auth/timelapse/:ke/:id',
|
||||
config.webPaths.apiPrefix+':auth/timelapse/:ke/:id/:date',
|
||||
], function (req,res){
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
s.auth(req.params,function(user){
|
||||
var hasRestrictions = user.details.sub && user.details.allmonitors !== '1'
|
||||
if(
|
||||
user.permissions.watch_videos==="0" ||
|
||||
hasRestrictions && (!user.details.video_view || user.details.video_view.indexOf(req.params.id)===-1)
|
||||
){
|
||||
res.end(s.prettyPrint([]))
|
||||
return
|
||||
}
|
||||
req.sql='SELECT * FROM `Timelapse Frames` WHERE ke=?';req.ar=[req.params.ke];
|
||||
if(req.query.archived=='1'){
|
||||
req.sql+=' AND details LIKE \'%"archived":"1"\''
|
||||
}
|
||||
if(!req.params.id){
|
||||
if(user.details.sub&&user.details.monitors&&user.details.allmonitors!=='1'){
|
||||
try{user.details.monitors=JSON.parse(user.details.monitors);}catch(er){}
|
||||
req.or=[];
|
||||
user.details.monitors.forEach(function(v,n){
|
||||
req.or.push('mid=?');req.ar.push(v)
|
||||
})
|
||||
req.sql+=' AND ('+req.or.join(' OR ')+')'
|
||||
}
|
||||
}else{
|
||||
if(!user.details.sub||user.details.allmonitors!=='0'||user.details.monitors.indexOf(req.params.id)>-1){
|
||||
req.sql+=' and mid=?'
|
||||
req.ar.push(req.params.id)
|
||||
}else{
|
||||
res.end('[]');
|
||||
return;
|
||||
}
|
||||
}
|
||||
var isMp4Call = false
|
||||
if(req.query.mp4){
|
||||
isMp4Call = true
|
||||
}
|
||||
if(req.params.date){
|
||||
if(req.params.date.indexOf('-') === -1 && !isNaN(req.params.date)){
|
||||
req.params.date = parseInt(req.params.date)
|
||||
}
|
||||
var selectedDate = req.params.date
|
||||
if(typeof req.params.date === 'string' && req.params.date.indexOf('.') > -1){
|
||||
isMp4Call = true
|
||||
selectedDate = req.params.date.split('.')[0]
|
||||
}
|
||||
selectedDate = new Date(selectedDate)
|
||||
var utcSelectedDate = new Date(selectedDate.getTime() + selectedDate.getTimezoneOffset() * 60000)
|
||||
req.query.start = moment(utcSelectedDate).format('YYYY-MM-DD HH:mm:ss')
|
||||
var dayAfter = utcSelectedDate
|
||||
dayAfter.setDate(dayAfter.getDate() + 1)
|
||||
req.query.end = moment(dayAfter).format('YYYY-MM-DD HH:mm:ss')
|
||||
}
|
||||
if(req.query.start||req.query.end){
|
||||
if(!req.query.startOperator||req.query.startOperator==''){
|
||||
req.query.startOperator='>='
|
||||
}
|
||||
if(!req.query.endOperator||req.query.endOperator==''){
|
||||
req.query.endOperator='<='
|
||||
}
|
||||
if(req.query.start && req.query.start !== '' && req.query.end && req.query.end !== ''){
|
||||
req.query.start = s.stringToSqlTime(req.query.start)
|
||||
req.query.end = s.stringToSqlTime(req.query.end)
|
||||
req.sql+=' AND `time` '+req.query.startOperator+' ? AND `time` '+req.query.endOperator+' ?';
|
||||
req.ar.push(req.query.start)
|
||||
req.ar.push(req.query.end)
|
||||
}else if(req.query.start && req.query.start !== ''){
|
||||
req.query.start = s.stringToSqlTime(req.query.start)
|
||||
req.sql+=' AND `time` '+req.query.startOperator+' ?';
|
||||
req.ar.push(req.query.start)
|
||||
}
|
||||
}
|
||||
// if(!req.query.limit||req.query.limit==''){req.query.limit=288}
|
||||
req.sql+=' ORDER BY `time` DESC'
|
||||
s.sqlQuery(req.sql,req.ar,function(err,r){
|
||||
if(isMp4Call){
|
||||
if(r && r[0]){
|
||||
s.createVideoFromTimelapse(r,req.query.fps,function(response){
|
||||
if(response.fileExists){
|
||||
if(req.query.download){
|
||||
res.setHeader('Content-Type', 'video/mp4')
|
||||
s.streamMp4FileOverHttp(response.fileLocation,req,res)
|
||||
}else{
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.end(s.prettyPrint({
|
||||
ok : response.ok,
|
||||
fileExists : response.fileExists,
|
||||
msg : response.msg,
|
||||
}))
|
||||
}
|
||||
}else{
|
||||
res.setHeader('Content-Type', 'application/json')
|
||||
res.end(s.prettyPrint({
|
||||
ok : response.ok,
|
||||
fileExists : response.fileExists,
|
||||
msg : response.msg,
|
||||
}))
|
||||
}
|
||||
})
|
||||
}else{
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
res.end(s.prettyPrint([]))
|
||||
}
|
||||
}else{
|
||||
if(r && r[0]){
|
||||
r.forEach(function(file){
|
||||
file.details = s.parseJSON(file.details)
|
||||
})
|
||||
res.end(s.prettyPrint(r))
|
||||
}else{
|
||||
res.end(s.prettyPrint([]))
|
||||
}
|
||||
}
|
||||
})
|
||||
},res,req);
|
||||
});
|
||||
/**
|
||||
* API : Get Timelapse images
|
||||
*/
|
||||
app.get([
|
||||
config.webPaths.apiPrefix+':auth/timelapse/:ke/:id/:date/:filename',
|
||||
], function (req,res){
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
s.auth(req.params,function(user){
|
||||
var hasRestrictions = user.details.sub && user.details.allmonitors !== '1'
|
||||
if(
|
||||
user.permissions.watch_videos==="0" ||
|
||||
hasRestrictions && (!user.details.video_view || user.details.video_view.indexOf(req.params.id)===-1)
|
||||
){
|
||||
res.end(s.prettyPrint([]))
|
||||
return
|
||||
}
|
||||
req.sql='SELECT * FROM `Timelapse Frames` WHERE ke=?';req.ar=[req.params.ke];
|
||||
if(req.query.archived=='1'){
|
||||
req.sql+=' AND details LIKE \'%"archived":"1"\''
|
||||
}
|
||||
if(!req.params.id){
|
||||
if(user.details.sub&&user.details.monitors&&user.details.allmonitors!=='1'){
|
||||
try{user.details.monitors=JSON.parse(user.details.monitors);}catch(er){}
|
||||
req.or=[];
|
||||
user.details.monitors.forEach(function(v,n){
|
||||
req.or.push('mid=?');req.ar.push(v)
|
||||
})
|
||||
req.sql+=' AND ('+req.or.join(' OR ')+')'
|
||||
}
|
||||
}else{
|
||||
if(!user.details.sub||user.details.allmonitors!=='0'||user.details.monitors.indexOf(req.params.id)>-1){
|
||||
req.sql+=' and mid=?'
|
||||
req.ar.push(req.params.id)
|
||||
}else{
|
||||
res.end('[]');
|
||||
return;
|
||||
}
|
||||
}
|
||||
req.sql+=' AND filename=?'
|
||||
req.ar.push(req.params.filename)
|
||||
req.sql+=' ORDER BY `time` DESC'
|
||||
s.sqlQuery(req.sql,req.ar,function(err,r){
|
||||
if(r && r[0]){
|
||||
var frame = r[0]
|
||||
frame.details = s.parseJSON(frame.details)
|
||||
var fileLocation
|
||||
if(frame.details.dir){
|
||||
fileLocation = `${s.checkCorrectPathEnding(frame.details.dir)}`
|
||||
}else{
|
||||
fileLocation = `${s.dir.videos}`
|
||||
}
|
||||
var selectedDate = req.params.date
|
||||
if(selectedDate.indexOf('-') === -1){
|
||||
selectedDate = req.params.filename.split('T')[0]
|
||||
}
|
||||
fileLocation = `${fileLocation}${frame.ke}/${frame.mid}_timelapse/${selectedDate}/${req.params.filename}`
|
||||
fs.stat(fileLocation,function(err,stats){
|
||||
if(!err){
|
||||
res.contentType('image/jpeg')
|
||||
res.on('finish',function(){res.end()})
|
||||
fs.createReadStream(fileLocation).pipe(res)
|
||||
}else{
|
||||
res.end(s.prettyPrint({ok: false, msg: lang[`Nothing exists`]}))
|
||||
}
|
||||
})
|
||||
}else{
|
||||
res.end(s.prettyPrint({ok: false, msg: lang[`Nothing exists`]}))
|
||||
}
|
||||
})
|
||||
},res,req);
|
||||
});
|
||||
/**
|
||||
* Page : Get Timelapse Page (Not Modal)
|
||||
*/
|
||||
app.get(config.webPaths.apiPrefix+':auth/timelapsePage/:ke', function (req,res){
|
||||
req.params.protocol=req.protocol;
|
||||
s.auth(req.params,function(user){
|
||||
// if(user.permissions.watch_stream==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.monitors.indexOf(req.params.id)===-1){
|
||||
// res.end(user.lang['Not Permitted'])
|
||||
// return
|
||||
// }
|
||||
req.params.uid = user.uid
|
||||
s.renderPage(req,res,config.renderPaths.timelapse,{
|
||||
$user: user,
|
||||
data: req.params,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
lang: user.lang,
|
||||
originalURL: s.getOriginalUrl(req)
|
||||
})
|
||||
},res,req);
|
||||
});
|
||||
var buildTimelapseVideos = function(){
|
||||
var dateNow = new Date()
|
||||
var hoursNow = dateNow.getHours()
|
||||
if(hoursNow === 1){
|
||||
var dateNowMoment = moment(dateNow).utc().format('YYYY-MM-DDTHH:mm:ss')
|
||||
var dateMinusOneDay = moment(dateNow).utc().subtract(1, 'days').format('YYYY-MM-DDTHH:mm:ss')
|
||||
s.sqlQuery('SELECT * FROM `Timelapse Frames` WHERE time => ? AND time =< ?',[dateMinusOneDay,dateNowMoment],function(err,frames){
|
||||
console.log(frames.length)
|
||||
var groups = {}
|
||||
frames.forEach(function(frame){
|
||||
if(groups[frame.ke])groups[frame.ke] = {}
|
||||
if(groups[frame.ke][frame.mid])groups[frame.ke][frame.mid] = []
|
||||
groups[frame.ke][frame.mid].push(frame)
|
||||
})
|
||||
Object.keys(groups).forEach(function(groupKey){
|
||||
Object.keys(groups[groupKey]).forEach(function(monitorId){
|
||||
var frameSet = groups[groupKey][monitorId]
|
||||
s.createVideoFromTimelapse(frameSet,30,function(response){
|
||||
if(response.ok){
|
||||
|
||||
}
|
||||
console.log(response.fileLocation)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
// Auto Build Timelapse Videos
|
||||
if(config.autoBuildTimelapseVideosDaily === true){
|
||||
setInterval(buildTimelapseVideos,1000 * 60 * 60 * 0.75)//every 45 minutes
|
||||
buildTimelapseVideos()
|
||||
}
|
||||
}
|
|
@ -1,20 +1,21 @@
|
|||
module.exports = function(s,config,lang){
|
||||
config.uploaderEjsBlocks = []
|
||||
s.uploaderFields = []
|
||||
var loadLib = function(lib){
|
||||
var uploadersFolder = __dirname + '/uploaders/'
|
||||
var libraryPath = uploadersFolder + lib + '.js'
|
||||
var loadedLib = require(libraryPath)(s,config,lang)
|
||||
if(lib !== 'loader'){
|
||||
var libraryEjsFile = uploadersFolder + lib + '.ejs'
|
||||
config.uploaderEjsBlocks.push(libraryEjsFile)
|
||||
loadedLib.isFormGroupGroup = true
|
||||
s.uploaderFields.push(loadedLib)
|
||||
}
|
||||
return require(libraryPath)
|
||||
return loadedLib
|
||||
}
|
||||
loadLib('loader')(s,config,lang)
|
||||
loadLib('loader')
|
||||
//cloud storage
|
||||
loadLib('s3based')(s,config,lang)
|
||||
loadLib('backblazeB2')(s,config,lang)
|
||||
loadLib('amazonS3')(s,config,lang)
|
||||
loadLib('webdav')(s,config,lang)
|
||||
loadLib('s3based')
|
||||
loadLib('backblazeB2')
|
||||
loadLib('amazonS3')
|
||||
loadLib('webdav')
|
||||
//simple storage
|
||||
loadLib('sftp')(s,config,lang)
|
||||
loadLib('sftp')
|
||||
}
|
||||
|
|
|
@ -123,6 +123,67 @@ module.exports = function(s,config,lang){
|
|||
})
|
||||
}
|
||||
}
|
||||
var onInsertTimelapseFrame = function(monitorObject,queryInfo,filePath){
|
||||
var e = monitorObject
|
||||
if(s.group[e.ke].aws_s3 && s.group[e.ke].init.use_aws_s3 !== '0' && s.group[e.ke].init.aws_s3_save === '1'){
|
||||
var fileStream = fs.createReadStream(filePath)
|
||||
fileStream.on('error', function (err) {
|
||||
console.error(err)
|
||||
})
|
||||
var saveLocation = s.group[e.ke].init.aws_s3_dir + e.ke + '/' + e.mid + '_timelapse/' + queryInfo.filename
|
||||
s.group[e.ke].aws_s3.upload({
|
||||
Bucket: s.group[e.ke].init.aws_s3_bucket,
|
||||
Key: saveLocation,
|
||||
Body: fileStream,
|
||||
ACL:'public-read',
|
||||
ContentType:'image/jpeg'
|
||||
},function(err,data){
|
||||
if(err){
|
||||
s.userLog(e,{type:lang['Wasabi Hot Cloud Storage Upload Error'],msg:err})
|
||||
}
|
||||
if(s.group[e.ke].init.aws_s3_log === '1' && data && data.Location){
|
||||
var save = [
|
||||
queryInfo.mid,
|
||||
queryInfo.ke,
|
||||
queryInfo.time,
|
||||
s.s({
|
||||
type : 's3',
|
||||
location : saveLocation,
|
||||
}),
|
||||
queryInfo.size,
|
||||
data.Location
|
||||
]
|
||||
s.sqlQuery('INSERT INTO `Cloud Timelapse Frames` (mid,ke,time,details,size,href) VALUES (?,?,?,?,?,?)',save)
|
||||
s.setCloudDiskUsedForGroup(e,{
|
||||
amount : s.kilobyteToMegabyte(queryInfo.size),
|
||||
storageType : 's3'
|
||||
},'timelapseFrames')
|
||||
s.purgeCloudDiskForGroup(e,'s3','timelapseFrames')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
var onDeleteTimelapseFrameFromCloud = function(e,frame,callback){
|
||||
// e = user
|
||||
try{
|
||||
var frameDetails = JSON.parse(frame.details)
|
||||
}catch(err){
|
||||
var frameDetails = frame.details
|
||||
}
|
||||
if(frameDetails.type !== 's3'){
|
||||
return
|
||||
}
|
||||
if(!frameDetails.location){
|
||||
frameDetails.location = frame.href.split(locationUrl)[1]
|
||||
}
|
||||
s.group[e.ke].aws_s3.deleteObject({
|
||||
Bucket: s.group[e.ke].init.aws_s3_bucket,
|
||||
Key: frameDetails.location,
|
||||
}, function(err, data) {
|
||||
if (err) console.log(err);
|
||||
callback()
|
||||
});
|
||||
}
|
||||
//amazon s3
|
||||
s.addCloudUploader({
|
||||
name: 's3',
|
||||
|
@ -133,5 +194,215 @@ module.exports = function(s,config,lang){
|
|||
cloudDiskUseStartupExtensions: cloudDiskUseStartupForAmazonS3,
|
||||
beforeAccountSave: beforeAccountSaveForAmazonS3,
|
||||
onAccountSave: cloudDiskUseStartupForAmazonS3,
|
||||
onInsertTimelapseFrame: onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud: onDeleteTimelapseFrameFromCloud
|
||||
})
|
||||
}
|
||||
//return fields that will appear in settings
|
||||
return {
|
||||
"evaluation": "details.use_aws_s3 !== '0'",
|
||||
"name": lang["Amazon S3"],
|
||||
"color": "forestgreen",
|
||||
"info": [
|
||||
{
|
||||
"name": "detail=aws_s3_save",
|
||||
"selector":"autosave_aws_s3",
|
||||
"field": lang.Autosave,
|
||||
"description": "",
|
||||
"default": lang.No,
|
||||
"example": "",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Bucket,
|
||||
"name": "detail=aws_s3_bucket",
|
||||
"placeholder": "Example : slippery-seal",
|
||||
"form-group-class": "autosave_aws_s3_input autosave_aws_s3_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.aws_accessKeyId,
|
||||
"name": "detail=aws_accessKeyId",
|
||||
"form-group-class": "autosave_aws_s3_input autosave_aws_s3_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=aws_secretAccessKey",
|
||||
"fieldType":"password",
|
||||
"placeholder": "",
|
||||
"field": lang.aws_secretAccessKey,
|
||||
"form-group-class":"autosave_aws_s3_input autosave_aws_s3_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=aws_region",
|
||||
"field": lang.Region,
|
||||
"fieldType": "select",
|
||||
"form-group-class":"autosave_aws_s3_input autosave_aws_s3_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": "US West (N. California)",
|
||||
"value": "us-west-1"
|
||||
},
|
||||
{
|
||||
"name": "US West (Oregon)",
|
||||
"value": "us-west-2"
|
||||
},
|
||||
{
|
||||
"name": "US East (Ohio)",
|
||||
"value": "us-east-2"
|
||||
},
|
||||
{
|
||||
"name": "US East (N. Virginia)",
|
||||
"value": "us-east-1"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific (Mumbai)",
|
||||
"value": "ap-south-1"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific (Seoul)",
|
||||
"value": "ap-northeast-2"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific (Osaka-Local)**",
|
||||
"value": "ap-northeast-3"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific (Singapore)",
|
||||
"value": "ap-southeast-1"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific (Sydney)",
|
||||
"value": "ap-southeast-2"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific (Tokyo)",
|
||||
"value": "ap-northeast-1"
|
||||
},
|
||||
{
|
||||
"name": "Canada (Central)",
|
||||
"value": "ca-central-1"
|
||||
},
|
||||
{
|
||||
"name": "China (Beijing)",
|
||||
"value": "cn-north-1"
|
||||
},
|
||||
{
|
||||
"name": "China (Ningxia)",
|
||||
"value": "cn-northwest-1"
|
||||
},
|
||||
{
|
||||
"name": "EU (Frankfurt)",
|
||||
"value": "eu-central-1"
|
||||
},
|
||||
{
|
||||
"name": "EU (Ireland)",
|
||||
"value": "eu-west-1"
|
||||
},
|
||||
{
|
||||
"name": "EU (London)",
|
||||
"value": "eu-west-2"
|
||||
},
|
||||
{
|
||||
"name": "EU (Paris)",
|
||||
"value": "eu-west-3"
|
||||
},
|
||||
{
|
||||
"name": "South America (São Paulo)",
|
||||
"value": "sa-east-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=aws_s3_log",
|
||||
"field": lang['Save Links to Database'],
|
||||
"fieldType": "select",
|
||||
"selector": "h_s3sld",
|
||||
"form-group-class":"autosave_aws_s3_input autosave_aws_s3_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=use_aws_s3_size_limit",
|
||||
"field": lang['Use Max Storage Amount'],
|
||||
"fieldType": "select",
|
||||
"selector": "h_s3zl",
|
||||
"form-group-class":"autosave_aws_s3_input autosave_aws_s3_1",
|
||||
"form-group-class-pre-layer":"h_s3sld_input h_s3sld_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=aws_s3_size_limit",
|
||||
"field": lang['Max Storage Amount'],
|
||||
"form-group-class":"autosave_aws_s3_input autosave_aws_s3_1",
|
||||
"form-group-class-pre-layer":"h_s3sld_input h_s3sld_1",
|
||||
"description": "",
|
||||
"default": "10000",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=aws_s3_dir",
|
||||
"field": lang['Save Directory'],
|
||||
"form-group-class":"autosave_aws_s3_input autosave_aws_s3_1",
|
||||
"description": "",
|
||||
"default": "/",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
|
@ -167,4 +167,127 @@ module.exports = function(s,config,lang){
|
|||
beforeAccountSave: beforeAccountSaveForBackblazeB2,
|
||||
onAccountSave: cloudDiskUseStartupForBackblazeB2,
|
||||
})
|
||||
return {
|
||||
"evaluation": "details.use_bb_b2 !== '0'",
|
||||
"name": lang["Backblaze B2"],
|
||||
"color": "forestgreen",
|
||||
"info": [
|
||||
{
|
||||
"name": "detail=bb_b2_save",
|
||||
"selector":"autosave_bb_b2",
|
||||
"field": lang.Autosave,
|
||||
"description": "",
|
||||
"default": lang.No,
|
||||
"example": "",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Bucket,
|
||||
"name": "detail=bb_b2_bucket",
|
||||
"placeholder": "Example : slippery-seal",
|
||||
"form-group-class": "autosave_bb_b2_input autosave_bb_b2_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.keyId,
|
||||
"name": "detail=bb_b2_accountId",
|
||||
"form-group-class": "autosave_bb_b2_input autosave_bb_b2_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=bb_b2_applicationKey",
|
||||
"fieldType":"password",
|
||||
"placeholder": "XXXXXXXXXXXXXXXXXXXXXXXX.XXXXXXXXXXXXXXX_XXXXXXXXXXXXXXXXXX",
|
||||
"field": lang.applicationKey,
|
||||
"form-group-class":"autosave_bb_b2_input autosave_bb_b2_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=bb_b2_log",
|
||||
"field": lang['Save Links to Database'],
|
||||
"fieldType": "select",
|
||||
"selector": "h_b2sld",
|
||||
"form-group-class":"autosave_bb_b2_input autosave_bb_b2_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=use_bb_b2_size_limit",
|
||||
"field": lang['Use Max Storage Amount'],
|
||||
"fieldType": "select",
|
||||
"selector": "h_b2zl",
|
||||
"form-group-class":"autosave_bb_b2_input autosave_bb_b2_1",
|
||||
"form-group-class-pre-layer":"h_b2sld_input h_b2sld_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=bb_b2_size_limit",
|
||||
"field": lang['Max Storage Amount'],
|
||||
"form-group-class":"autosave_bb_b2_input autosave_bb_b2_1",
|
||||
"form-group-class-pre-layer":"h_b2sld_input h_b2sld_1",
|
||||
"description": "",
|
||||
"default": "10000",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=bb_b2_dir",
|
||||
"field": lang['Save Directory'],
|
||||
"form-group-class":"autosave_bb_b2_input autosave_bb_b2_1",
|
||||
"description": "",
|
||||
"default": "/",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ module.exports = function(s){
|
|||
s.insertCompletedVideoExtender(opt.insertCompletedVideoExtender)
|
||||
s.deleteVideoFromCloudExtensions[opt.name] = opt.deleteVideoFromCloudExtensions
|
||||
s.cloudDiskUseStartupExtensions[opt.name] = opt.cloudDiskUseStartupExtensions
|
||||
if(opt.onInsertTimelapseFrame)s.onInsertTimelapseFrame(opt.onInsertTimelapseFrame)
|
||||
if(opt.onDeleteTimelapseFrameFromCloud)s.onDeleteTimelapseFrameFromCloudExtensions[opt.name] = opt.onDeleteTimelapseFrameFromCloud
|
||||
s.beforeAccountSave(opt.beforeAccountSave)
|
||||
s.onAccountSave(opt.onAccountSave)
|
||||
s.cloudDisksLoader(opt.name)
|
||||
|
@ -13,6 +15,7 @@ module.exports = function(s){
|
|||
s.loadGroupAppExtender(opt.loadGroupAppExtender)
|
||||
s.unloadGroupAppExtender(opt.unloadGroupAppExtender)
|
||||
s.insertCompletedVideoExtender(opt.insertCompletedVideoExtender)
|
||||
if(opt.onInsertTimelapseFrame)s.onInsertTimelapseFrame(opt.onInsertTimelapseFrame)
|
||||
s.beforeAccountSave(opt.beforeAccountSave)
|
||||
s.onAccountSave(opt.onAccountSave)
|
||||
s.onMonitorSave(opt.onMonitorSave)
|
||||
|
|
|
@ -34,8 +34,6 @@ module.exports = function(s,config,lang){
|
|||
userDetails.whcs_accessKeyId !== ''&&
|
||||
userDetails.whcs_secretAccessKey &&
|
||||
userDetails.whcs_secretAccessKey !== ''&&
|
||||
userDetails.whcs_region &&
|
||||
userDetails.whcs_region !== ''&&
|
||||
userDetails.whcs_bucket !== ''
|
||||
){
|
||||
if(!userDetails.whcs_dir || userDetails.whcs_dir === '/'){
|
||||
|
@ -50,6 +48,10 @@ module.exports = function(s,config,lang){
|
|||
if(!userDetails.whcs_endpoint || userDetails.whcs_endpoint === ''){
|
||||
userDetails.whcs_endpoint = 's3.wasabisys.com'
|
||||
}
|
||||
var whcs_region = null
|
||||
if(userDetails.whcs_region && userDetails.whcs_region !== ''){
|
||||
whcs_region = userDetails.whcs_region
|
||||
}
|
||||
var endpointSplit = userDetails.whcs_endpoint.split('.')
|
||||
if(endpointSplit.length > 2){
|
||||
endpointSplit.shift()
|
||||
|
@ -62,7 +64,7 @@ module.exports = function(s,config,lang){
|
|||
endpoint: wasabiEndpoint,
|
||||
accessKeyId: userDetails.whcs_accessKeyId,
|
||||
secretAccessKey: userDetails.whcs_secretAccessKey,
|
||||
region: userDetails.whcs_region
|
||||
region: whcs_region
|
||||
})
|
||||
s.group[e.ke].whcs = new s.group[e.ke].whcs.S3();
|
||||
}
|
||||
|
@ -100,9 +102,10 @@ module.exports = function(s,config,lang){
|
|||
fileStream.on('error', function (err) {
|
||||
console.error(err)
|
||||
})
|
||||
var bucketName = s.group[e.ke].init.whcs_bucket
|
||||
var saveLocation = s.group[e.ke].init.whcs_dir+e.ke+'/'+e.mid+'/'+k.filename
|
||||
s.group[e.ke].whcs.upload({
|
||||
Bucket: s.group[e.ke].init.whcs_bucket,
|
||||
Bucket: bucketName,
|
||||
Key: saveLocation,
|
||||
Body:fileStream,
|
||||
ACL:'public-read',
|
||||
|
@ -112,6 +115,8 @@ module.exports = function(s,config,lang){
|
|||
s.userLog(e,{type:lang['Wasabi Hot Cloud Storage Upload Error'],msg:err})
|
||||
}
|
||||
if(s.group[e.ke].init.whcs_log === '1' && data && data.Location){
|
||||
var cloudLink = data.Location
|
||||
cloudLink = fixCloudianUrl(e,cloudLink)
|
||||
var save = [
|
||||
e.mid,
|
||||
e.ke,
|
||||
|
@ -123,7 +128,7 @@ module.exports = function(s,config,lang){
|
|||
}),
|
||||
k.filesize,
|
||||
k.endTime,
|
||||
data.Location
|
||||
cloudLink
|
||||
]
|
||||
s.sqlQuery('INSERT INTO `Cloud Videos` (mid,ke,time,status,details,size,end,href) VALUES (?,?,?,?,?,?,?,?)',save)
|
||||
s.setCloudDiskUsedForGroup(e,{
|
||||
|
@ -135,6 +140,83 @@ module.exports = function(s,config,lang){
|
|||
})
|
||||
}
|
||||
}
|
||||
var onInsertTimelapseFrame = function(monitorObject,queryInfo,filePath){
|
||||
var e = monitorObject
|
||||
if(s.group[e.ke].whcs && s.group[e.ke].init.use_whcs !== '0' && s.group[e.ke].init.whcs_save === '1'){
|
||||
var fileStream = fs.createReadStream(filePath)
|
||||
fileStream.on('error', function (err) {
|
||||
console.error(err)
|
||||
})
|
||||
var saveLocation = s.group[e.ke].init.whcs_dir + e.ke + '/' + e.mid + '_timelapse/' + queryInfo.filename
|
||||
s.group[e.ke].whcs.upload({
|
||||
Bucket: s.group[e.ke].init.whcs_bucket,
|
||||
Key: saveLocation,
|
||||
Body: fileStream,
|
||||
ACL:'public-read',
|
||||
ContentType:'image/jpeg'
|
||||
},function(err,data){
|
||||
if(err){
|
||||
s.userLog(e,{type:lang['Wasabi Hot Cloud Storage Upload Error'],msg:err})
|
||||
}
|
||||
if(s.group[e.ke].init.whcs_log === '1' && data && data.Location){
|
||||
var save = [
|
||||
queryInfo.mid,
|
||||
queryInfo.ke,
|
||||
queryInfo.time,
|
||||
s.s({
|
||||
type : 'whcs',
|
||||
location : saveLocation,
|
||||
}),
|
||||
queryInfo.size,
|
||||
data.Location
|
||||
]
|
||||
s.sqlQuery('INSERT INTO `Cloud Timelapse Frames` (mid,ke,time,details,size,href) VALUES (?,?,?,?,?,?)',save)
|
||||
s.setCloudDiskUsedForGroup(e,{
|
||||
amount : s.kilobyteToMegabyte(queryInfo.size),
|
||||
storageType : 'whcs'
|
||||
},'timelapseFrames')
|
||||
s.purgeCloudDiskForGroup(e,'whcs','timelapseFrames')
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
var onDeleteTimelapseFrameFromCloud = function(e,frame,callback){
|
||||
// e = user
|
||||
try{
|
||||
var frameDetails = JSON.parse(frame.details)
|
||||
}catch(err){
|
||||
var frameDetails = frame.details
|
||||
}
|
||||
if(frameDetails.type !== 'whcs'){
|
||||
return
|
||||
}
|
||||
if(!frameDetails.location){
|
||||
frameDetails.location = frame.href.split(locationUrl)[1]
|
||||
}
|
||||
s.group[e.ke].whcs.deleteObject({
|
||||
Bucket: s.group[e.ke].init.whcs_bucket,
|
||||
Key: frameDetails.location,
|
||||
}, function(err, data) {
|
||||
if (err) console.log(err);
|
||||
callback()
|
||||
});
|
||||
}
|
||||
var fixCloudianUrl = function(e,cloudLink){
|
||||
if(cloudLink.indexOf('http') === -1){
|
||||
var bucketName = s.group[e.ke].init.whcs_bucket
|
||||
var endPointSplit = s.group[e.ke].init.whcs_endpoint.split('://')
|
||||
endPoint = endPointSplit[1] || endPointSplit[0]
|
||||
var protocol = `https`
|
||||
if(endPointSplit[1])protocol = endPointSplit[0]
|
||||
var cloudLinkPrefix = `${protocol}://${bucketName}.${endPoint}`
|
||||
var truncatedLink = cloudLink.substring(0, bucketName.length + 3)
|
||||
if(truncatedLink.indexOf(`${bucketName}/`) > -1){
|
||||
cloudLink = cloudLink.replace(`${bucketName}/`,'')
|
||||
}
|
||||
cloudLink = s.checkCorrectPathEnding(cloudLinkPrefix) + cloudLink
|
||||
}
|
||||
return cloudLink
|
||||
}
|
||||
//wasabi
|
||||
s.addCloudUploader({
|
||||
name: 'whcs',
|
||||
|
@ -145,5 +227,250 @@ module.exports = function(s,config,lang){
|
|||
cloudDiskUseStartupExtensions: cloudDiskUseStartupForWasabiHotCloudStorage,
|
||||
beforeAccountSave: beforeAccountSaveForWasabiHotCloudStorage,
|
||||
onAccountSave: cloudDiskUseStartupForWasabiHotCloudStorage,
|
||||
onInsertTimelapseFrame: onInsertTimelapseFrame,
|
||||
onDeleteTimelapseFrameFromCloud: onDeleteTimelapseFrameFromCloud
|
||||
})
|
||||
return {
|
||||
"evaluation": "details.use_whcs !== '0'",
|
||||
"name": lang["S3-Based Network Storage"],
|
||||
"color": "forestgreen",
|
||||
"info": [
|
||||
{
|
||||
"name": "detail=whcs_save",
|
||||
"selector":"autosave_whcs",
|
||||
"field": lang.Autosave,
|
||||
"description": "",
|
||||
"default": lang.No,
|
||||
"example": "",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=use_whcs_endpoint_select",
|
||||
"selector":"h_whcs_endpoint",
|
||||
"field": lang.Endpoint,
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": "Custom Endpoint",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": lang['Wasabi Hot Cloud Storage'],
|
||||
"value": "s3.wasabisys.com"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang['Endpoint Address'],
|
||||
"name": "detail=whcs_endpoint",
|
||||
"placeholder": "s3.wasabisys.com",
|
||||
"form-group-class": "autosave_whcs_input autosave_whcs_1",
|
||||
"form-group-class-pre-layer":"h_whcs_endpoint_input h_whcs_endpoint_",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Bucket,
|
||||
"name": "detail=whcs_bucket",
|
||||
"placeholder": "Example : slippery-seal",
|
||||
"form-group-class": "autosave_whcs_input autosave_whcs_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.aws_accessKeyId,
|
||||
"name": "detail=whcs_accessKeyId",
|
||||
"form-group-class": "autosave_whcs_input autosave_whcs_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=whcs_secretAccessKey",
|
||||
"fieldType":"password",
|
||||
"placeholder": "",
|
||||
"field": lang.aws_secretAccessKey,
|
||||
"form-group-class":"autosave_whcs_input autosave_whcs_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=whcs_region",
|
||||
"field": lang.Region,
|
||||
"fieldType": "select",
|
||||
"form-group-class":"autosave_whcs_input autosave_whcs_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang['No Region'],
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "US West 1",
|
||||
"value": "us-west-1"
|
||||
},
|
||||
{
|
||||
"name": "US West 2)",
|
||||
"value": "us-west-2"
|
||||
},
|
||||
{
|
||||
"name": "US East 1",
|
||||
"value": "us-east-2"
|
||||
},
|
||||
{
|
||||
"name": "US East 2",
|
||||
"value": "us-east-1"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific 1",
|
||||
"value": "ap-south-1"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific 2",
|
||||
"value": "ap-northeast-2"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific 3",
|
||||
"value": "ap-northeast-3"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific 4",
|
||||
"value": "ap-southeast-1"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific 5",
|
||||
"value": "ap-southeast-2"
|
||||
},
|
||||
{
|
||||
"name": "Asia Pacific 6",
|
||||
"value": "ap-northeast-1"
|
||||
},
|
||||
{
|
||||
"name": "Canada 1",
|
||||
"value": "ca-central-1"
|
||||
},
|
||||
{
|
||||
"name": "China 1",
|
||||
"value": "cn-north-1"
|
||||
},
|
||||
{
|
||||
"name": "China 1",
|
||||
"value": "cn-northwest-1"
|
||||
},
|
||||
{
|
||||
"name": "EU 1",
|
||||
"value": "eu-central-1"
|
||||
},
|
||||
{
|
||||
"name": "EU 2",
|
||||
"value": "eu-west-1"
|
||||
},
|
||||
{
|
||||
"name": "EU 3",
|
||||
"value": "eu-west-2"
|
||||
},
|
||||
{
|
||||
"name": "EU 4",
|
||||
"value": "eu-west-3"
|
||||
},
|
||||
{
|
||||
"name": "South America 1",
|
||||
"value": "sa-east-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=whcs_log",
|
||||
"field": lang['Save Links to Database'],
|
||||
"fieldType": "select",
|
||||
"selector": "h_whcssld",
|
||||
"form-group-class":"autosave_whcs_input autosave_whcs_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=use_whcs_size_limit",
|
||||
"field": lang['Use Max Storage Amount'],
|
||||
"fieldType": "select",
|
||||
"selector": "h_whcszl",
|
||||
"form-group-class":"autosave_whcs_input autosave_whcs_1",
|
||||
"form-group-class-pre-layer":"h_whcssld_input h_whcssld_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=whcs_size_limit",
|
||||
"field": lang['Max Storage Amount'],
|
||||
"form-group-class":"autosave_whcs_input autosave_whcs_1",
|
||||
"form-group-class-pre-layer":"h_whcssld_input h_whcssld_1",
|
||||
"description": "",
|
||||
"default": "10000",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=whcs_dir",
|
||||
"field": lang['Save Directory'],
|
||||
"form-group-class":"autosave_whcs_input autosave_whcs_1",
|
||||
"description": "",
|
||||
"default": "/",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,8 +72,8 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
var onAccountSaveForSftp = function(group,userDetails,user){
|
||||
if(s.group[user.ke] && s.group[user.ke].sftp && s.group[user.ke].init.use_sftp !== '0' && s.group[user.ke].init.sftp_save === '1'){
|
||||
Object.keys(s.group[user.ke].mon_conf).forEach(function(monitorId){
|
||||
createSftpDirectory(s.group[user.ke].mon_conf[monitorId])
|
||||
Object.keys(s.group[user.ke].rawMonitorConfigurations).forEach(function(monitorId){
|
||||
createSftpDirectory(s.group[user.ke].rawMonitorConfigurations[monitorId])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -87,4 +87,92 @@ module.exports = function(s,config,lang){
|
|||
onAccountSave: onAccountSaveForSftp,
|
||||
onMonitorSave: onMonitorSaveForSftp,
|
||||
})
|
||||
return {
|
||||
"evaluation": "details.use_sftp !== '0'",
|
||||
"name": lang['SFTP (SSH File Transfer)'],
|
||||
"color": "forestgreen",
|
||||
"info": [
|
||||
{
|
||||
"name": "detail=sftp_save",
|
||||
"selector":"autosave_sftp",
|
||||
"field": lang.Autosave,
|
||||
"description": "",
|
||||
"default": lang.No,
|
||||
"example": "",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Host,
|
||||
"name": "detail=sftp_host",
|
||||
"form-group-class": "autosave_sftp_input autosave_sftp_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Port,
|
||||
"name": "detail=sftp_port",
|
||||
"form-group-class": "autosave_sftp_input autosave_sftp_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Username,
|
||||
"name": "detail=sftp_username",
|
||||
"form-group-class": "autosave_sftp_input autosave_sftp_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Password,
|
||||
"fieldType": "password",
|
||||
"name": "detail=sftp_password",
|
||||
"form-group-class": "autosave_sftp_input autosave_sftp_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.privateKey,
|
||||
"fieldType": "textarea",
|
||||
"name": "detail=sftp_privateKey",
|
||||
"form-group-class": "autosave_sftp_input autosave_sftp_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=sftp_dir",
|
||||
"field": lang['Save Directory'],
|
||||
"form-group-class":"autosave_sftp_input autosave_sftp_1",
|
||||
"description": "",
|
||||
"default": "/",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -76,7 +76,7 @@ module.exports = function(s,config,lang){
|
|||
if(wfs && s.group[e.ke].init.use_webdav !== '0' && s.group[e.ke].init.webdav_save === "1"){
|
||||
var webdavUploadDir = s.group[e.ke].init.webdav_dir+e.ke+'/'+e.mid+'/'
|
||||
var startWebDavUpload = function(){
|
||||
s.group[e.ke].mon[e.id].webdavDirExist = true
|
||||
s.group[e.ke].activeMonitors[e.id].webdavDirExist = true
|
||||
var wfsWriteStream =
|
||||
fs.createReadStream(k.dir + k.filename).pipe(wfs.createWriteStream(webdavUploadDir + k.filename))
|
||||
if(s.group[e.ke].init.webdav_log === '1'){
|
||||
|
@ -102,7 +102,7 @@ module.exports = function(s,config,lang){
|
|||
s.purgeCloudDiskForGroup(e,'webdav')
|
||||
}
|
||||
}
|
||||
if(s.group[e.ke].mon[e.id].webdavDirExist !== true){
|
||||
if(s.group[e.ke].activeMonitors[e.id].webdavDirExist !== true){
|
||||
//check if webdav dir exist
|
||||
var parentPoint = 0
|
||||
var webDavParentz = webdavUploadDir.split('/')
|
||||
|
@ -166,4 +166,125 @@ module.exports = function(s,config,lang){
|
|||
beforeAccountSave: beforeAccountSaveForWebDav,
|
||||
onAccountSave: cloudDiskUseStartupForWebDav,
|
||||
})
|
||||
return {
|
||||
"evaluation": "details.use_webdav !== '0'",
|
||||
"name": lang.WebDAV,
|
||||
"color": "forestgreen",
|
||||
"info": [
|
||||
{
|
||||
"name": "detail=webdav_save",
|
||||
"selector":"autosave_webdav",
|
||||
"field": lang.Autosave,
|
||||
"description": "",
|
||||
"default": lang.No,
|
||||
"example": "",
|
||||
"fieldType": "select",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.URL,
|
||||
"name": "detail=webdav_url",
|
||||
"form-group-class": "autosave_webdav_input autosave_webdav_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Username,
|
||||
"name": "detail=webdav_user",
|
||||
"form-group-class": "autosave_webdav_input autosave_webdav_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"field": lang.Password,
|
||||
"fieldType": "password",
|
||||
"name": "detail=webdav_pass",
|
||||
"form-group-class": "autosave_webdav_input autosave_webdav_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=webdav_log",
|
||||
"field": lang['Save Links to Database'],
|
||||
"fieldType": "select",
|
||||
"selector": "h_webdavsld",
|
||||
"form-group-class":"autosave_webdav_input autosave_webdav_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=use_webdav_size_limit",
|
||||
"field": lang['Use Max Storage Amount'],
|
||||
"fieldType": "select",
|
||||
"selector": "h_webdavzl",
|
||||
"form-group-class":"autosave_webdav_input autosave_webdav_1",
|
||||
"form-group-class-pre-layer":"h_webdavsld_input h_webdavsld_1",
|
||||
"description": "",
|
||||
"default": "",
|
||||
"example": "",
|
||||
"possible": [
|
||||
{
|
||||
"name": lang.No,
|
||||
"value": "0"
|
||||
},
|
||||
{
|
||||
"name": lang.Yes,
|
||||
"value": "1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=webdav_size_limit",
|
||||
"field": lang['Max Storage Amount'],
|
||||
"form-group-class":"autosave_webdav_input autosave_webdav_1",
|
||||
"form-group-class-pre-layer":"h_webdavsld_input h_webdavsld_1",
|
||||
"description": "",
|
||||
"default": "10000",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
{
|
||||
"hidden": true,
|
||||
"name": "detail=webdav_dir",
|
||||
"field": lang['Save Directory'],
|
||||
"form-group-class":"autosave_webdav_input autosave_webdav_1",
|
||||
"description": "",
|
||||
"default": "/",
|
||||
"example": "",
|
||||
"possible": ""
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
549
libs/user.js
549
libs/user.js
|
@ -2,80 +2,262 @@ var fs = require('fs');
|
|||
var events = require('events');
|
||||
var spawn = require('child_process').spawn;
|
||||
var exec = require('child_process').exec;
|
||||
module.exports = function(s,config){
|
||||
module.exports = function(s,config,lang){
|
||||
s.purgeDiskForGroup = function(e){
|
||||
if(config.cron.deleteOverMax === true){
|
||||
s.group[e.ke].sizePurgeQueue.push(1)
|
||||
if(s.group[e.ke].sizePurging !== true){
|
||||
s.group[e.ke].sizePurging = true
|
||||
var finish = function(){
|
||||
//remove value just used from queue
|
||||
s.group[e.ke].sizePurgeQueue.shift()
|
||||
//do next one
|
||||
if(s.group[e.ke].sizePurgeQueue.length > 0){
|
||||
checkQueue()
|
||||
if(config.cron.deleteOverMax === true && s.group[e.ke] && s.group[e.ke].sizePurgeQueue){
|
||||
s.group[e.ke].sizePurgeQueue.push(1)
|
||||
if(s.group[e.ke].sizePurging !== true){
|
||||
s.group[e.ke].sizePurging = true
|
||||
var finish = function(){
|
||||
//remove value just used from queue
|
||||
s.group[e.ke].sizePurgeQueue.shift()
|
||||
//do next one
|
||||
if(s.group[e.ke].sizePurgeQueue.length > 0){
|
||||
checkQueue()
|
||||
}else{
|
||||
s.group[e.ke].sizePurging = false
|
||||
s.sendDiskUsedAmountToClients(e)
|
||||
}
|
||||
}
|
||||
var checkQueue = function(){
|
||||
//get first in queue
|
||||
var currentPurge = s.group[e.ke].sizePurgeQueue[0]
|
||||
var reRunCheck = function(){}
|
||||
var deleteSetOfVideos = function(err,videos,storageIndex,callback){
|
||||
var videosToDelete = []
|
||||
var queryValues = [e.ke]
|
||||
var completedCheck = 0
|
||||
if(videos){
|
||||
videos.forEach(function(video){
|
||||
video.dir = s.getVideoDirectory(video) + s.formattedTime(video.time) + '.' + video.ext
|
||||
videosToDelete.push('(mid=? AND `time`=?)')
|
||||
queryValues.push(video.mid)
|
||||
queryValues.push(video.time)
|
||||
fs.chmod(video.dir,0o777,function(err){
|
||||
fs.unlink(video.dir,function(err){
|
||||
++completedCheck
|
||||
if(err){
|
||||
fs.stat(video.dir,function(err){
|
||||
if(!err){
|
||||
s.file('delete',video.dir)
|
||||
}
|
||||
})
|
||||
}
|
||||
if(videosToDelete.length === completedCheck){
|
||||
videosToDelete = videosToDelete.join(' OR ')
|
||||
s.sqlQuery('DELETE FROM Videos WHERE ke =? AND ('+videosToDelete+')',queryValues,function(){
|
||||
reRunCheck()
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
if(storageIndex){
|
||||
s.setDiskUsedForGroupAddStorage(e,{
|
||||
size: -(video.size/1000000),
|
||||
storageIndex: storageIndex
|
||||
})
|
||||
}else{
|
||||
s.setDiskUsedForGroup(e,-(video.size/1000000))
|
||||
}
|
||||
s.tx({
|
||||
f: 'video_delete',
|
||||
ff: 'over_max',
|
||||
filename: s.formattedTime(video.time)+'.'+video.ext,
|
||||
mid: video.mid,
|
||||
ke: video.ke,
|
||||
time: video.time,
|
||||
end: s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')
|
||||
},'GRP_'+e.ke)
|
||||
})
|
||||
}else{
|
||||
s.group[e.ke].sizePurging = false
|
||||
s.sendDiskUsedAmountToClients(e)
|
||||
console.log(err)
|
||||
}
|
||||
if(videosToDelete.length === 0){
|
||||
if(callback)callback()
|
||||
}
|
||||
}
|
||||
var checkQueue = function(){
|
||||
//get first in queue
|
||||
var currentPurge = s.group[e.ke].sizePurgeQueue[0]
|
||||
var deleteVideos = function(){
|
||||
//run purge command
|
||||
if(s.group[e.ke].usedSpace > (s.group[e.ke].sizeLimit*config.cron.deleteOverMaxOffset)){
|
||||
s.sqlQuery('SELECT * FROM Videos WHERE status != 0 AND details NOT LIKE \'%"archived":"1"%\' AND ke=? ORDER BY `time` ASC LIMIT 3',[e.ke],function(err,videos){
|
||||
var videosToDelete = []
|
||||
var queryValues = [e.ke]
|
||||
var completedCheck = 0
|
||||
if(videos){
|
||||
videos.forEach(function(video){
|
||||
video.dir = s.getVideoDirectory(video) + s.formattedTime(video.time) + '.' + video.ext
|
||||
videosToDelete.push('(mid=? AND `time`=?)')
|
||||
queryValues.push(video.mid)
|
||||
queryValues.push(video.time)
|
||||
fs.chmod(video.dir,0o777,function(err){
|
||||
fs.unlink(video.dir,function(err){
|
||||
++completedCheck
|
||||
if(err){
|
||||
fs.stat(video.dir,function(err){
|
||||
if(!err){
|
||||
s.file('delete',video.dir)
|
||||
}
|
||||
})
|
||||
}
|
||||
if(videosToDelete.length === completedCheck){
|
||||
videosToDelete = videosToDelete.join(' OR ')
|
||||
s.sqlQuery('DELETE FROM Videos WHERE ke =? AND ('+videosToDelete+')',queryValues,function(){
|
||||
deleteVideos()
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
||||
s.setDiskUsedForGroup(e,-(video.size/1000000))
|
||||
s.tx({
|
||||
f: 'video_delete',
|
||||
ff: 'over_max',
|
||||
filename: s.formattedTime(video.time)+'.'+video.ext,
|
||||
mid: video.mid,
|
||||
ke: video.ke,
|
||||
time: video.time,
|
||||
end: s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')
|
||||
},'GRP_'+e.ke)
|
||||
var deleteSetOfTimelapseFrames = function(err,frames,storageIndex,callback){
|
||||
var framesToDelete = []
|
||||
var queryValues = [e.ke]
|
||||
var completedCheck = 0
|
||||
if(frames){
|
||||
frames.forEach(function(frame){
|
||||
var selectedDate = frame.filename.split('T')[0]
|
||||
var dir = s.getTimelapseFrameDirectory(frame)
|
||||
var fileLocationMid = `${dir}` + frame.filename
|
||||
framesToDelete.push('(mid=? AND `time`=?)')
|
||||
queryValues.push(frame.mid)
|
||||
queryValues.push(frame.time)
|
||||
fs.unlink(fileLocationMid,function(err){
|
||||
++completedCheck
|
||||
if(err){
|
||||
fs.stat(fileLocationMid,function(err){
|
||||
if(!err){
|
||||
s.file('delete',fileLocationMid)
|
||||
}
|
||||
})
|
||||
}else{
|
||||
console.log(err)
|
||||
}
|
||||
if(videosToDelete.length === 0){
|
||||
finish()
|
||||
if(framesToDelete.length === completedCheck){
|
||||
framesToDelete = framesToDelete.join(' OR ')
|
||||
s.sqlQuery('DELETE FROM `Timelapse Frames` WHERE ke =? AND ('+framesToDelete+')',queryValues,function(){
|
||||
reRunCheck()
|
||||
})
|
||||
}
|
||||
})
|
||||
if(storageIndex){
|
||||
s.setDiskUsedForGroupAddStorage(e,{
|
||||
size: -(frame.size/1000000),
|
||||
storageIndex: storageIndex
|
||||
},'timelapeFrames')
|
||||
}else{
|
||||
s.setDiskUsedForGroup(e,-(frame.size/1000000),'timelapeFrames')
|
||||
}
|
||||
// s.tx({
|
||||
// f: 'timelapse_frame_delete',
|
||||
// ff: 'over_max',
|
||||
// filename: s.formattedTime(video.time)+'.'+video.ext,
|
||||
// mid: video.mid,
|
||||
// ke: video.ke,
|
||||
// time: video.time,
|
||||
// end: s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')
|
||||
// },'GRP_'+e.ke)
|
||||
})
|
||||
}else{
|
||||
finish()
|
||||
console.log(err)
|
||||
}
|
||||
if(framesToDelete.length === 0){
|
||||
if(callback)callback()
|
||||
}
|
||||
}
|
||||
deleteVideos()
|
||||
var deleteSetOfFileBinFiles = function(err,files,storageIndex,callback){
|
||||
var filesToDelete = []
|
||||
var queryValues = [e.ke]
|
||||
var completedCheck = 0
|
||||
if(files){
|
||||
files.forEach(function(file){
|
||||
var dir = s.getFileBinDirectory(file)
|
||||
var fileLocationMid = `${dir}` + file.name
|
||||
filesToDelete.push('(mid=? AND `name`=?)')
|
||||
queryValues.push(file.mid)
|
||||
queryValues.push(file.name)
|
||||
fs.unlink(fileLocationMid,function(err){
|
||||
++completedCheck
|
||||
if(err){
|
||||
fs.stat(fileLocationMid,function(err){
|
||||
if(!err){
|
||||
s.file('delete',fileLocationMid)
|
||||
}
|
||||
})
|
||||
}
|
||||
if(filesToDelete.length === completedCheck){
|
||||
filesToDelete = filesToDelete.join(' OR ')
|
||||
s.sqlQuery('DELETE FROM `Files` WHERE ke =? AND ('+filesToDelete+')',queryValues,function(){
|
||||
reRunCheck()
|
||||
})
|
||||
}
|
||||
})
|
||||
if(storageIndex){
|
||||
s.setDiskUsedForGroupAddStorage(e,{
|
||||
size: -(file.size/1000000),
|
||||
storageIndex: storageIndex
|
||||
},'fileBin')
|
||||
}else{
|
||||
s.setDiskUsedForGroup(e,-(file.size/1000000),'fileBin')
|
||||
}
|
||||
})
|
||||
}else{
|
||||
console.log(err)
|
||||
}
|
||||
if(framesToDelete.length === 0){
|
||||
if(callback)callback()
|
||||
}
|
||||
}
|
||||
var deleteMainVideos = function(callback){
|
||||
reRunCheck = function(){
|
||||
return deleteMainVideos(callback)
|
||||
}
|
||||
//run purge command
|
||||
if(s.group[e.ke].usedSpaceVideos > (s.group[e.ke].sizeLimit * (s.group[e.ke].sizeLimitVideoPercent / 100) * config.cron.deleteOverMaxOffset)){
|
||||
s.sqlQuery('SELECT * FROM Videos WHERE status != 0 AND details NOT LIKE \'%"archived":"1"%\' AND ke=? AND details NOT LIKE \'%"dir"%\' ORDER BY `time` ASC LIMIT 3',[e.ke],function(err,rows){
|
||||
deleteSetOfVideos(err,rows,null,callback)
|
||||
})
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
}
|
||||
var deleteAddStorageVideos = function(callback){
|
||||
reRunCheck = function(){
|
||||
return deleteAddStorageVideos(callback)
|
||||
}
|
||||
var currentStorageNumber = 0
|
||||
var readStorageArray = function(finishedReading){
|
||||
setTimeout(function(){
|
||||
reRunCheck = readStorageArray
|
||||
var storage = s.listOfStorage[currentStorageNumber]
|
||||
if(!storage){
|
||||
//done all checks, move on to next user
|
||||
callback()
|
||||
return
|
||||
}
|
||||
var storageId = storage.value
|
||||
if(storageId === '' || !s.group[e.ke].addStorageUse[storageId]){
|
||||
++currentStorageNumber
|
||||
readStorageArray()
|
||||
return
|
||||
}
|
||||
var storageIndex = s.group[e.ke].addStorageUse[storageId]
|
||||
//run purge command
|
||||
if(storageIndex.usedSpace > (storageIndex.sizeLimit * (storageIndex.deleteOffset || config.cron.deleteOverMaxOffset))){
|
||||
s.sqlQuery('SELECT * FROM Videos WHERE status != 0 AND details NOT LIKE \'%"archived":"1"%\' AND ke=? AND details LIKE ? ORDER BY `time` ASC LIMIT 3',[e.ke,`%"dir":"${storage.value}"%`],function(err,rows){
|
||||
deleteSetOfVideos(err,rows,storageIndex,callback)
|
||||
})
|
||||
}else{
|
||||
++currentStorageNumber
|
||||
readStorageArray()
|
||||
}
|
||||
})
|
||||
}
|
||||
readStorageArray()
|
||||
}
|
||||
var deleteTimelapseFrames = function(callback){
|
||||
reRunCheck = function(){
|
||||
return deleteTimelapseFrames(callback)
|
||||
}
|
||||
//run purge command
|
||||
if(s.group[e.ke].usedSpaceTimelapseFrames > (s.group[e.ke].sizeLimit * (s.group[e.ke].sizeLimitTimelapseFramesPercent / 100) * config.cron.deleteOverMaxOffset)){
|
||||
s.sqlQuery('SELECT * FROM `Timelapse Frames` WHERE ke=? AND details NOT LIKE \'%"archived":"1"%\' ORDER BY `time` ASC LIMIT 3',[e.ke],function(err,frames){
|
||||
deleteSetOfTimelapseFrames(err,frames,null,callback)
|
||||
})
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
}
|
||||
var deleteFileBinFiles = function(callback){
|
||||
if(config.deleteFileBinsOverMax === true){
|
||||
reRunCheck = function(){
|
||||
return deleteSetOfFileBinFiles(callback)
|
||||
}
|
||||
//run purge command
|
||||
if(s.group[e.ke].usedSpaceFileBin > (s.group[e.ke].sizeLimit * (s.group[e.ke].sizeLimitFileBinPercent / 100) * config.cron.deleteOverMaxOffset)){
|
||||
s.sqlQuery('SELECT * FROM `Files` WHERE ke=? ORDER BY `time` ASC LIMIT 1',[e.ke],function(err,frames){
|
||||
deleteSetOfFileBinFiles(err,frames,null,callback)
|
||||
})
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
}
|
||||
deleteMainVideos(function(){
|
||||
deleteTimelapseFrames(function(){
|
||||
deleteFileBinFiles(function(){
|
||||
deleteAddStorageVideos(function(){
|
||||
finish()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
checkQueue()
|
||||
}
|
||||
|
@ -83,27 +265,41 @@ module.exports = function(s,config){
|
|||
s.sendDiskUsedAmountToClients(e)
|
||||
}
|
||||
}
|
||||
s.setDiskUsedForGroup = function(e,bytes){
|
||||
s.setDiskUsedForGroup = function(e,bytes,storagePoint){
|
||||
//`bytes` will be used as the value to add or substract
|
||||
if(s.group[e.ke] && s.group[e.ke].diskUsedEmitter){
|
||||
s.group[e.ke].diskUsedEmitter.emit('set',bytes)
|
||||
s.group[e.ke].diskUsedEmitter.emit('set',bytes,storagePoint)
|
||||
}
|
||||
}
|
||||
s.purgeCloudDiskForGroup = function(e,storageType){
|
||||
if(s.group[e.ke].diskUsedEmitter){
|
||||
s.group[e.ke].diskUsedEmitter.emit('purgeCloud',storageType)
|
||||
s.setDiskUsedForGroupAddStorage = function(e,data,storagePoint){
|
||||
if(s.group[e.ke] && s.group[e.ke].diskUsedEmitter){
|
||||
s.group[e.ke].diskUsedEmitter.emit('setAddStorage',data,storagePoint)
|
||||
}
|
||||
}
|
||||
s.setCloudDiskUsedForGroup = function(e,usage){
|
||||
//`bytes` will be used as the value to add or substract
|
||||
s.purgeCloudDiskForGroup = function(e,storageType,storagePoint){
|
||||
if(s.group[e.ke].diskUsedEmitter){
|
||||
s.group[e.ke].diskUsedEmitter.emit('setCloud',usage)
|
||||
s.group[e.ke].diskUsedEmitter.emit('purgeCloud',storageType,storagePoint)
|
||||
}
|
||||
}
|
||||
s.setCloudDiskUsedForGroup = function(e,usage,storagePoint){
|
||||
//`usage` will be used as the value to add or substract
|
||||
if(s.group[e.ke].diskUsedEmitter){
|
||||
s.group[e.ke].diskUsedEmitter.emit('setCloud',usage,storagePoint)
|
||||
}
|
||||
}
|
||||
s.sendDiskUsedAmountToClients = function(e){
|
||||
//send the amount used disk space to connected users
|
||||
if(s.group[e.ke]&&s.group[e.ke].init){
|
||||
s.tx({f:'diskUsed',size:s.group[e.ke].usedSpace,limit:s.group[e.ke].sizeLimit},'GRP_'+e.ke);
|
||||
s.tx({
|
||||
f: 'diskUsed',
|
||||
size: s.group[e.ke].usedSpace,
|
||||
usedSpace: s.group[e.ke].usedSpace,
|
||||
usedSpaceVideos: s.group[e.ke].usedSpaceVideos,
|
||||
usedSpaceFilebin: s.group[e.ke].usedSpaceFilebin,
|
||||
usedSpaceTimelapseFrames: s.group[e.ke].usedSpaceTimelapseFrames,
|
||||
limit: s.group[e.ke].sizeLimit,
|
||||
addStorage: s.group[e.ke].addStorageUse
|
||||
},'GRP_'+e.ke);
|
||||
}
|
||||
}
|
||||
//user log
|
||||
|
@ -125,15 +321,20 @@ module.exports = function(s,config){
|
|||
if(!s.group[e.ke].init){
|
||||
s.group[e.ke].init={}
|
||||
}
|
||||
if(!s.group[e.ke].addStorageUse){s.group[e.ke].addStorageUse={}};
|
||||
if(!s.group[e.ke].fileBin){s.group[e.ke].fileBin={}};
|
||||
if(!s.group[e.ke].users){s.group[e.ke].users={}}
|
||||
if(!s.group[e.ke].dashcamUsers){s.group[e.ke].dashcamUsers={}}
|
||||
if(!s.group[e.ke].sizePurgeQueue){s.group[e.ke].sizePurgeQueue=[]}
|
||||
if(!s.group[e.ke].addStorageUse){s.group[e.ke].addStorageUse = {}}
|
||||
if(!e.limit||e.limit===''){e.limit=10000}else{e.limit=parseFloat(e.limit)}
|
||||
//save global space limit for group key (mb)
|
||||
s.group[e.ke].sizeLimit=e.limit;
|
||||
s.group[e.ke].sizeLimit = e.limit || s.group[e.ke].sizeLimit || 10000
|
||||
s.group[e.ke].sizeLimitVideoPercent = parseFloat(s.group[e.ke].init.size_video_percent) || 90
|
||||
s.group[e.ke].sizeLimitTimelapseFramesPercent = parseFloat(s.group[e.ke].init.size_timelapse_percent) || 5
|
||||
s.group[e.ke].sizeLimitFileBinPercent = parseFloat(s.group[e.ke].init.size_filebin_percent) || 5
|
||||
//save global used space as megabyte value
|
||||
s.group[e.ke].usedSpace=e.size/1000000;
|
||||
s.group[e.ke].usedSpace = s.group[e.ke].usedSpace || ((e.size || 0) / 1000000)
|
||||
//emit the changes to connected users
|
||||
s.sendDiskUsedAmountToClients(e)
|
||||
}
|
||||
|
@ -143,9 +344,9 @@ module.exports = function(s,config){
|
|||
s.group[e.ke].init={};
|
||||
}
|
||||
s.sqlQuery('SELECT * FROM Users WHERE ke=? AND details NOT LIKE ?',[e.ke,'%"sub"%'],function(ar,r){
|
||||
if(r&&r[0]){
|
||||
r=r[0];
|
||||
ar=JSON.parse(r.details);
|
||||
if(r && r[0]){
|
||||
r = r[0];
|
||||
ar = JSON.parse(r.details);
|
||||
//load extenders
|
||||
s.loadGroupAppExtensions.forEach(function(extender){
|
||||
extender(r,ar)
|
||||
|
@ -153,7 +354,7 @@ module.exports = function(s,config){
|
|||
//disk Used Emitter
|
||||
if(!s.group[e.ke].diskUsedEmitter){
|
||||
s.group[e.ke].diskUsedEmitter = new events.EventEmitter()
|
||||
s.group[e.ke].diskUsedEmitter.on('setCloud',function(currentChange){
|
||||
s.group[e.ke].diskUsedEmitter.on('setCloud',function(currentChange,storagePoint){
|
||||
var amount = currentChange.amount
|
||||
var storageType = currentChange.storageType
|
||||
var cloudDisk = s.group[e.ke].cloudDiskUse[storageType]
|
||||
|
@ -168,52 +369,96 @@ module.exports = function(s,config){
|
|||
}
|
||||
//change global size value
|
||||
cloudDisk.usedSpace = cloudDisk.usedSpace + amount
|
||||
switch(storagePoint){
|
||||
case'timelapeFrames':
|
||||
cloudDisk.usedSpaceTimelapseFrames += amount
|
||||
break;
|
||||
case'fileBin':
|
||||
cloudDisk.usedSpaceFilebin += amount
|
||||
break;
|
||||
default:
|
||||
cloudDisk.usedSpaceVideos += amount
|
||||
break;
|
||||
}
|
||||
})
|
||||
s.group[e.ke].diskUsedEmitter.on('purgeCloud',function(storageType){
|
||||
s.group[e.ke].diskUsedEmitter.on('purgeCloud',function(storageType,storagePoint){
|
||||
if(config.cron.deleteOverMax === true){
|
||||
//set queue processor
|
||||
var finish=function(){
|
||||
// s.sendDiskUsedAmountToClients(e)
|
||||
}
|
||||
var deleteVideos = function(){
|
||||
//run purge command
|
||||
var cloudDisk = s.group[e.ke].cloudDiskUse[storageType]
|
||||
if(cloudDisk.sizeLimitCheck && cloudDisk.usedSpace > (cloudDisk.sizeLimit*config.cron.deleteOverMaxOffset)){
|
||||
s.sqlQuery('SELECT * FROM `Cloud Videos` WHERE status != 0 AND ke=? AND details LIKE \'%"type":"'+storageType+'"%\' ORDER BY `time` ASC LIMIT 2',[e.ke],function(err,videos){
|
||||
var videosToDelete = []
|
||||
var queryValues = [e.ke]
|
||||
if(!videos)return console.log(err)
|
||||
videos.forEach(function(video){
|
||||
video.dir = s.getVideoDirectory(video) + s.formattedTime(video.time) + '.' + video.ext
|
||||
videosToDelete.push('(mid=? AND `time`=?)')
|
||||
queryValues.push(video.mid)
|
||||
queryValues.push(video.time)
|
||||
s.setCloudDiskUsedForGroup(e,{
|
||||
amount : -(video.size/1000000),
|
||||
storageType : storageType
|
||||
})
|
||||
s.deleteVideoFromCloudExtensionsRunner(e,storageType,video)
|
||||
var cloudDisk = s.group[e.ke].cloudDiskUse[storageType]
|
||||
//set queue processor
|
||||
var finish=function(){
|
||||
// s.sendDiskUsedAmountToClients(e)
|
||||
}
|
||||
var deleteVideos = function(){
|
||||
//run purge command
|
||||
if(cloudDisk.sizeLimitCheck && cloudDisk.usedSpace > (cloudDisk.sizeLimit*config.cron.deleteOverMaxOffset)){
|
||||
s.sqlQuery('SELECT * FROM `Cloud Videos` WHERE status != 0 AND ke=? AND details LIKE \'%"type":"'+storageType+'"%\' ORDER BY `time` ASC LIMIT 2',[e.ke],function(err,videos){
|
||||
var videosToDelete = []
|
||||
var queryValues = [e.ke]
|
||||
if(!videos)return console.log(err)
|
||||
videos.forEach(function(video){
|
||||
video.dir = s.getVideoDirectory(video) + s.formattedTime(video.time) + '.' + video.ext
|
||||
videosToDelete.push('(mid=? AND `time`=?)')
|
||||
queryValues.push(video.mid)
|
||||
queryValues.push(video.time)
|
||||
s.setCloudDiskUsedForGroup(e,{
|
||||
amount : -(video.size/1000000),
|
||||
storageType : storageType
|
||||
})
|
||||
if(videosToDelete.length > 0){
|
||||
videosToDelete = videosToDelete.join(' OR ')
|
||||
s.sqlQuery('DELETE FROM `Cloud Videos` WHERE ke =? AND ('+videosToDelete+')',queryValues,function(){
|
||||
deleteVideos()
|
||||
})
|
||||
}else{
|
||||
finish()
|
||||
}
|
||||
s.deleteVideoFromCloudExtensionsRunner(e,storageType,video)
|
||||
})
|
||||
}else{
|
||||
finish()
|
||||
}
|
||||
if(videosToDelete.length > 0){
|
||||
videosToDelete = videosToDelete.join(' OR ')
|
||||
s.sqlQuery('DELETE FROM `Cloud Videos` WHERE ke =? AND ('+videosToDelete+')',queryValues,function(){
|
||||
deleteVideos()
|
||||
})
|
||||
}else{
|
||||
finish()
|
||||
}
|
||||
})
|
||||
}else{
|
||||
finish()
|
||||
}
|
||||
deleteVideos()
|
||||
}
|
||||
var deleteTimelapseFrames = function(callback){
|
||||
reRunCheck = function(){
|
||||
return deleteTimelapseFrames(callback)
|
||||
}
|
||||
//run purge command
|
||||
if(cloudDisk.usedSpaceTimelapseFrames > (cloudDisk.sizeLimit * (s.group[e.ke].sizeLimitTimelapseFramesPercent / 100) * config.cron.deleteOverMaxOffset)){
|
||||
s.sqlQuery('SELECT * FROM `Cloud Timelapse Frames` WHERE ke=? AND details NOT LIKE \'%"archived":"1"%\' ORDER BY `time` ASC LIMIT 3',[e.ke],function(err,frames){
|
||||
var framesToDelete = []
|
||||
var queryValues = [e.ke]
|
||||
if(!frames)return console.log(err)
|
||||
frames.forEach(function(frame){
|
||||
frame.dir = s.getVideoDirectory(frame) + s.formattedTime(frame.time) + '.' + frame.ext
|
||||
framesToDelete.push('(mid=? AND `time`=?)')
|
||||
queryValues.push(frame.mid)
|
||||
queryValues.push(frame.time)
|
||||
s.setCloudDiskUsedForGroup(e,{
|
||||
amount : -(frame.size/1000000),
|
||||
storageType : storageType
|
||||
})
|
||||
s.deleteVideoFromCloudExtensionsRunner(e,storageType,frame)
|
||||
})
|
||||
s.sqlQuery('DELETE FROM `Cloud Timelapse Frames` WHERE ke =? AND ('+framesToDelete+')',queryValues,function(){
|
||||
deleteTimelapseFrames(callback)
|
||||
})
|
||||
})
|
||||
}else{
|
||||
callback()
|
||||
}
|
||||
}
|
||||
deleteVideos(function(){
|
||||
deleteTimelapseFrames(function(){
|
||||
|
||||
})
|
||||
})
|
||||
}else{
|
||||
// s.sendDiskUsedAmountToClients(e)
|
||||
}
|
||||
})
|
||||
//s.setDiskUsedForGroup
|
||||
s.group[e.ke].diskUsedEmitter.on('set',function(currentChange){
|
||||
s.group[e.ke].diskUsedEmitter.on('set',function(currentChange,storageType){
|
||||
//validate current values
|
||||
if(!s.group[e.ke].usedSpace){
|
||||
s.group[e.ke].usedSpace=0
|
||||
|
@ -225,12 +470,51 @@ module.exports = function(s,config){
|
|||
}
|
||||
//change global size value
|
||||
s.group[e.ke].usedSpace += currentChange
|
||||
switch(storageType){
|
||||
case'timelapeFrames':
|
||||
s.group[e.ke].usedSpaceTimelapseFrames += currentChange
|
||||
break;
|
||||
case'fileBin':
|
||||
s.group[e.ke].usedSpaceFilebin += currentChange
|
||||
break;
|
||||
default:
|
||||
s.group[e.ke].usedSpaceVideos += currentChange
|
||||
break;
|
||||
}
|
||||
//remove value just used from queue
|
||||
s.sendDiskUsedAmountToClients(e)
|
||||
})
|
||||
s.group[e.ke].diskUsedEmitter.on('setAddStorage',function(data,storageType){
|
||||
var currentSize = data.size
|
||||
var storageIndex = data.storageIndex
|
||||
//validate current values
|
||||
if(!storageIndex.usedSpace){
|
||||
storageIndex.usedSpace = 0
|
||||
}else{
|
||||
storageIndex.usedSpace = parseFloat(storageIndex.usedSpace)
|
||||
}
|
||||
if(storageIndex.usedSpace < 0 || isNaN(storageIndex.usedSpace)){
|
||||
storageIndex.usedSpace = 0
|
||||
}
|
||||
//change global size value
|
||||
storageIndex.usedSpace += currentSize
|
||||
switch(storageType){
|
||||
case'timelapeFrames':
|
||||
storageIndex.usedSpaceTimelapseFrames += currentSize
|
||||
break;
|
||||
case'fileBin':
|
||||
storageIndex.usedSpaceFilebin += currentSize
|
||||
break;
|
||||
default:
|
||||
storageIndex.usedSpaceVideos += currentSize
|
||||
break;
|
||||
}
|
||||
//remove value just used from queue
|
||||
s.sendDiskUsedAmountToClients(e)
|
||||
})
|
||||
}
|
||||
Object.keys(ar).forEach(function(v){
|
||||
s.group[e.ke].init[v]=ar[v]
|
||||
s.group[e.ke].init[v] = ar[v]
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -259,6 +543,7 @@ module.exports = function(s,config){
|
|||
d.form.details.edit_days=d.d.edit_days
|
||||
d.form.details.use_admin=d.d.use_admin
|
||||
d.form.details.use_ldap=d.d.use_ldap
|
||||
d.form.details.landing_page=d.d.landing_page
|
||||
//check
|
||||
if(d.d.edit_days == "0"){
|
||||
d.form.details.days = d.d.days;
|
||||
|
@ -278,8 +563,38 @@ module.exports = function(s,config){
|
|||
if(d.d.days){d.form.details.days=d.d.days;}
|
||||
delete(d.form.details.mon_groups)
|
||||
}
|
||||
var newSize = d.form.details.size || 10000
|
||||
d.form.details=JSON.stringify(d.form.details)
|
||||
var newSize = parseFloat(d.form.details.size) || 10000
|
||||
//load addStorageUse
|
||||
var currentStorageNumber = 0
|
||||
var readStorageArray = function(){
|
||||
var storage = s.listOfStorage[currentStorageNumber]
|
||||
if(!storage){
|
||||
//done all checks, move on to next user
|
||||
return
|
||||
}
|
||||
var path = storage.value
|
||||
if(path === ''){
|
||||
++currentStorageNumber
|
||||
readStorageArray()
|
||||
return
|
||||
}
|
||||
var detailContainer = d.form.details || s.group[r.ke].init
|
||||
var storageId = path
|
||||
var detailsContainerAddStorage = s.parseJSON(detailContainer.addStorage)
|
||||
if(!s.group[d.ke].addStorageUse[storageId])s.group[d.ke].addStorageUse[storageId] = {}
|
||||
var storageIndex = s.group[d.ke].addStorageUse[storageId]
|
||||
storageIndex.name = storage.name
|
||||
storageIndex.path = path
|
||||
storageIndex.usedSpace = storageIndex.usedSpace || 0
|
||||
if(detailsContainerAddStorage && detailsContainerAddStorage[path] && detailsContainerAddStorage[path].limit){
|
||||
storageIndex.sizeLimit = parseFloat(detailsContainerAddStorage[path].limit)
|
||||
}else{
|
||||
storageIndex.sizeLimit = newSize
|
||||
}
|
||||
}
|
||||
readStorageArray()
|
||||
///
|
||||
d.form.details = JSON.stringify(d.form.details)
|
||||
///
|
||||
d.set=[],d.ar=[];
|
||||
if(d.form.pass&&d.form.pass!==''){d.form.pass=s.createHash(d.form.pass);}else{delete(d.form.pass)};
|
||||
|
|
20
libs/version.js
Normal file
20
libs/version.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
var exec = require('child_process').exec
|
||||
module.exports = function(s,config,lang,app,io){
|
||||
var getRepositoryCommitId = function(callback){
|
||||
exec(`git rev-parse HEAD`,function(err,response){
|
||||
if(response){
|
||||
var data = response.toString()
|
||||
var isGitRespository = false
|
||||
if(data.indexOf('not a git repository') === -1){
|
||||
s.currentVersion = data
|
||||
isGitRespository = true
|
||||
s.systemLog(`Current Version : ${s.currentVersion}`)
|
||||
}
|
||||
}else if(err){
|
||||
s.debugLog('Git is not installed.')
|
||||
}
|
||||
if(callback)callback(!isGitRespository,data)
|
||||
})
|
||||
}
|
||||
getRepositoryCommitId()
|
||||
}
|
65
libs/videoDropInServer.js
Normal file
65
libs/videoDropInServer.js
Normal file
|
@ -0,0 +1,65 @@
|
|||
var fs = require('fs')
|
||||
var express = require('express')
|
||||
module.exports = function(s,config,lang,app,io){
|
||||
if(config.videoDropInServer === true){
|
||||
if(!config.videoDropInServerPort)config.videoDropInServerPort = 420
|
||||
if(!config.videoDropInServerUrl)config.videoDropInServerUrl = `ftp://0.0.0.0:${config.videoDropInServerPort}`
|
||||
config.videoDropInServerUrl = config.videoDropInServerUrl.replace('{{PORT}}',config.videoDropInServerPort)
|
||||
const FtpSrv = require('ftp-srv')
|
||||
const videoDropInServer = new FtpSrv({
|
||||
url: config.videoDropInServerUrl,
|
||||
// log:{trace:function(){},error:function(){},child:function(){},info:function(){},warn:function(){}
|
||||
})
|
||||
|
||||
videoDropInServer.on('login', (data, resolve, reject) => {
|
||||
var username = data.username
|
||||
var password = data.password
|
||||
s.basicOrApiAuthentication(username,password,function(err,user){
|
||||
if(user){
|
||||
data.connection.on('STOR', (error, filePath) => {
|
||||
if(!error && filePath){
|
||||
var filenameParts = filePath.replace(s.dir.videos + user.ke + '/','').split('/')
|
||||
var ke = user.ke
|
||||
var mid = filenameParts[0].replace('_timelapse','')
|
||||
var monitor = s.group[ke].rawMonitorConfigurations[mid]
|
||||
var filename = filenameParts[filenameParts.length - 1]
|
||||
if(s.isCorrectFilenameSyntax(filename)){
|
||||
if(filenameParts[0].indexOf('_timelapse')){
|
||||
var fileStats = fs.statSync(filePath)
|
||||
var details = {}
|
||||
if(monitor.details && monitor.details.dir && monitor.details.dir !== ''){
|
||||
details.dir = monitor.details.dir
|
||||
}
|
||||
var timeNow = new Date(s.nameToTime(filename))
|
||||
s.sqlQuery('INSERT INTO `Timelapse Frames` (ke,mid,details,filename,size,time) VALUES (?,?,?,?,?,?)',[ke,mid,s.s(details),filename,fileStats.size,timeNow])
|
||||
s.setDiskUsedForGroup(monitor,fileStats.size / 1000000)
|
||||
}
|
||||
// else{
|
||||
// s.insertDatabaseRow(
|
||||
// monitor,
|
||||
// {
|
||||
//
|
||||
// }
|
||||
// )
|
||||
// console.log(filename)
|
||||
// }
|
||||
}else{
|
||||
console.log('Incorrect Filename Syntax')
|
||||
}
|
||||
}else{
|
||||
s.systemLog(error)
|
||||
}
|
||||
})
|
||||
resolve({root: s.dir.videos + user.ke})
|
||||
}else{
|
||||
// reject(new Error('Failed Authorization'))
|
||||
}
|
||||
})
|
||||
})
|
||||
videoDropInServer.listen().then(() => {
|
||||
s.systemLog(`Video Drop-In Server (FTP) running on port ${config.videoDropInServerPort}...`)
|
||||
}).catch(function(err){
|
||||
s.systemLog(err)
|
||||
})
|
||||
}
|
||||
}
|
178
libs/videos.js
178
libs/videos.js
|
@ -26,7 +26,7 @@ module.exports = function(s,config,lang){
|
|||
*/
|
||||
s.buildVideoLinks = function(videos,options){
|
||||
videos.forEach(function(v){
|
||||
var details = JSON.parse(v.details)
|
||||
var details = s.parseJSON(v.details)
|
||||
var queryString = []
|
||||
if(details.isUTC === true){
|
||||
queryString.push('isUTC=true')
|
||||
|
@ -45,7 +45,7 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
v.filename = s.formattedTime(v.time)+'.'+v.ext;
|
||||
if(!options.videoParam)options.videoParam = 'videos'
|
||||
var href = '/'+options.auth+'/'+options.videoParam+'/'+v.ke+'/'+v.mid+'/'+v.filename;
|
||||
var href = s.checkCorrectPathEnding(config.webPaths.apiPrefix) + options.auth+'/'+options.videoParam+'/'+v.ke+'/'+v.mid+'/'+v.filename;
|
||||
v.actionUrl = href
|
||||
v.links = {
|
||||
deleteVideo : href+'/delete' + queryString,
|
||||
|
@ -56,16 +56,11 @@ module.exports = function(s,config,lang){
|
|||
v.details = details
|
||||
})
|
||||
}
|
||||
//extender for "s.insertCompletedVideo"
|
||||
s.insertCompletedVideoExtensions = []
|
||||
s.insertCompletedVideoExtender = function(callback){
|
||||
s.insertCompletedVideoExtensions.push(callback)
|
||||
}
|
||||
s.insertDatabaseRow = function(e,k,callback){
|
||||
s.checkDetails(e)
|
||||
//save database row
|
||||
k.details = {}
|
||||
if(e.details&&e.details.dir&&e.details.dir!==''){
|
||||
if(!k.details)k.details = {}
|
||||
if(e.details && e.details.dir && e.details.dir !== ''){
|
||||
k.details.dir = e.details.dir
|
||||
}
|
||||
if(config.useUTC === true)k.details.isUTC = config.useUTC;
|
||||
|
@ -94,8 +89,8 @@ module.exports = function(s,config,lang){
|
|||
if(!k)k={};
|
||||
e.dir = s.getVideoDirectory(e)
|
||||
k.dir = e.dir.toString()
|
||||
if(s.group[e.ke].mon[e.id].childNode){
|
||||
s.cx({f:'insertCompleted',d:s.group[e.ke].mon_conf[e.id],k:k},s.group[e.ke].mon[e.id].childNodeId);
|
||||
if(s.group[e.ke].activeMonitors[e.id].childNode){
|
||||
s.cx({f:'insertCompleted',d:s.group[e.ke].rawMonitorConfigurations[e.id],k:k},s.group[e.ke].activeMonitors[e.id].childNodeId);
|
||||
}else{
|
||||
//get file directory
|
||||
k.fileExists = fs.existsSync(k.dir+k.file)
|
||||
|
@ -113,6 +108,7 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
if(k.fileExists===true){
|
||||
//close video row
|
||||
k.details = {}
|
||||
k.stat = fs.statSync(k.dir+k.file)
|
||||
k.filesize = k.stat.size
|
||||
k.filesizeMB = parseFloat((k.filesize/1000000).toFixed(2))
|
||||
|
@ -145,8 +141,8 @@ module.exports = function(s,config,lang){
|
|||
})
|
||||
})
|
||||
.on('close',function(){
|
||||
clearTimeout(s.group[e.ke].mon[e.id].recordingChecker)
|
||||
clearTimeout(s.group[e.ke].mon[e.id].streamChecker)
|
||||
clearTimeout(s.group[e.ke].activeMonitors[e.id].recordingChecker)
|
||||
clearTimeout(s.group[e.ke].activeMonitors[e.id].streamChecker)
|
||||
s.cx({
|
||||
f:'created_file',
|
||||
mid:e.id,
|
||||
|
@ -174,7 +170,18 @@ module.exports = function(s,config,lang){
|
|||
//purge over max
|
||||
s.purgeDiskForGroup(e)
|
||||
//send new diskUsage values
|
||||
s.setDiskUsedForGroup(e,k.filesizeMB)
|
||||
var storageIndex = s.getVideoStorageIndex(e)
|
||||
if(storageIndex){
|
||||
s.setDiskUsedForGroupAddStorage(e,{
|
||||
size: k.filesizeMB,
|
||||
storageIndex: storageIndex
|
||||
})
|
||||
}else{
|
||||
s.setDiskUsedForGroup(e,k.filesizeMB)
|
||||
}
|
||||
s.onBeforeInsertCompletedVideoExtensions.forEach(function(extender){
|
||||
extender(e,k)
|
||||
})
|
||||
s.insertDatabaseRow(e,k,callback)
|
||||
s.insertCompletedVideoExtensions.forEach(function(extender){
|
||||
extender(e,k)
|
||||
|
@ -216,7 +223,15 @@ module.exports = function(s,config,lang){
|
|||
time: s.nameToTime(filename),
|
||||
end: s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')
|
||||
},'GRP_'+e.ke);
|
||||
s.setDiskUsedForGroup(e,-(r.size / 1000000))
|
||||
var storageIndex = s.getVideoStorageIndex(e)
|
||||
if(storageIndex){
|
||||
s.setDiskUsedForGroupAddStorage(e,{
|
||||
size: -(r.size / 1000000),
|
||||
storageIndex: storageIndex
|
||||
})
|
||||
}else{
|
||||
s.setDiskUsedForGroup(e,-(r.size / 1000000))
|
||||
}
|
||||
s.sqlQuery('DELETE FROM Videos WHERE `mid`=? AND `ke`=? AND `time`=?',queryValues,function(err){
|
||||
if(err){
|
||||
s.systemLog(lang['File Delete Error'] + ' : '+e.ke+' : '+' : '+e.id,err)
|
||||
|
@ -270,7 +285,15 @@ module.exports = function(s,config,lang){
|
|||
time: s.nameToTime(filename),
|
||||
end: s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')
|
||||
},'GRP_'+video.ke);
|
||||
s.setDiskUsedForGroup(video,-(video.size / 1000000))
|
||||
var storageIndex = s.getVideoStorageIndex(video)
|
||||
if(storageIndex){
|
||||
s.setDiskUsedForGroupAddStorage(video,{
|
||||
size: -(video.size / 1000000),
|
||||
storageIndex: storageIndex
|
||||
})
|
||||
}else{
|
||||
s.setDiskUsedForGroup(video,-(video.size / 1000000))
|
||||
}
|
||||
fs.unlink(video.dir+filename,function(err){
|
||||
fs.stat(video.dir+filename,function(err){
|
||||
if(!err){
|
||||
|
@ -334,8 +357,9 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
if(forceCheck === true || config.insertOrphans === true){
|
||||
if(!checkMax){
|
||||
checkMax = config.orphanedVideoCheckMax
|
||||
checkMax = config.orphanedVideoCheckMax || 2
|
||||
}
|
||||
|
||||
var videosDirectory = s.getVideoDirectory(monitor)// + s.formattedTime(video.time) + '.' + video.ext
|
||||
fs.readdir(videosDirectory,function(err,files){
|
||||
if(files && files.length > 0){
|
||||
|
@ -380,7 +404,7 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
s.streamMp4FileOverHttp = function(filePath,req,res){
|
||||
var ext = filePath.split('.')
|
||||
ext = filePath[filePath.length - 1]
|
||||
ext = ext[ext.length - 1]
|
||||
var total = fs.statSync(filePath).size;
|
||||
if (req.headers['range']) {
|
||||
try{
|
||||
|
@ -392,15 +416,15 @@ module.exports = function(s,config,lang){
|
|||
var end = partialend ? parseInt(partialend, 10) : total-1;
|
||||
var chunksize = (end-start)+1;
|
||||
var file = fs.createReadStream(filePath, {start: start, end: end});
|
||||
req.headerWrite={ 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/'+req.ext }
|
||||
req.headerWrite={ 'Content-Range': 'bytes ' + start + '-' + end + '/' + total, 'Accept-Ranges': 'bytes', 'Content-Length': chunksize, 'Content-Type': 'video/'+ext }
|
||||
req.writeCode=206
|
||||
}catch(err){
|
||||
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+req.ext};
|
||||
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+ext};
|
||||
var file = fs.createReadStream(filePath)
|
||||
req.writeCode=200
|
||||
}
|
||||
} else {
|
||||
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+req.ext};
|
||||
req.headerWrite={ 'Content-Length': total, 'Content-Type': 'video/'+ext};
|
||||
var file = fs.createReadStream(filePath)
|
||||
req.writeCode=200
|
||||
}
|
||||
|
@ -414,4 +438,116 @@ module.exports = function(s,config,lang){
|
|||
file.pipe(res)
|
||||
return file
|
||||
}
|
||||
s.createVideoFromTimelapse = function(timelapseFrames,framesPerSecond,callback){
|
||||
framesPerSecond = parseInt(framesPerSecond)
|
||||
if(!framesPerSecond || isNaN(framesPerSecond))framesPerSecond = 2
|
||||
var frames = timelapseFrames.reverse()
|
||||
var ke = frames[0].ke
|
||||
var mid = frames[0].mid
|
||||
var finalFileName = frames[0].filename.split('.')[0] + '_' + frames[frames.length - 1].filename.split('.')[0] + `-${framesPerSecond}fps`
|
||||
var concatFiles = []
|
||||
var createLocation
|
||||
frames.forEach(function(frame,frameNumber){
|
||||
var selectedDate = frame.filename.split('T')[0]
|
||||
var fileLocationMid = `${frame.ke}/${frame.mid}_timelapse/${selectedDate}/`
|
||||
frame.details = s.parseJSON(frame.details)
|
||||
var fileLocation
|
||||
if(frame.details.dir){
|
||||
fileLocation = `${s.checkCorrectPathEnding(frame.details.dir)}`
|
||||
}else{
|
||||
fileLocation = `${s.dir.videos}`
|
||||
}
|
||||
fileLocation = `${fileLocation}${fileLocationMid}${frame.filename}`
|
||||
concatFiles.push(fileLocation)
|
||||
if(frameNumber === 0){
|
||||
createLocation = fileLocationMid
|
||||
}
|
||||
})
|
||||
if(concatFiles.length > 30){
|
||||
var commandTempLocation = `${s.dir.streams}${ke}/${mid}/mergeJpegs_${finalFileName}.sh`
|
||||
var finalMp4OutputLocation = `${s.dir.fileBin}${ke}/${mid}/${finalFileName}.mp4`
|
||||
if(!s.group[ke].activeMonitors[mid].buildingTimelapseVideo){
|
||||
if(!fs.existsSync(finalMp4OutputLocation)){
|
||||
var currentFile = 0
|
||||
var completionTimeout
|
||||
var commandString = `ffmpeg -y -pattern_type glob -f image2pipe -vcodec mjpeg -r ${framesPerSecond} -analyzeduration 10 -i - -q:v 1 -c:v libx264 -r ${framesPerSecond} "${finalMp4OutputLocation}"`
|
||||
fs.writeFileSync(commandTempLocation,commandString)
|
||||
var videoBuildProcess = spawn('sh',[commandTempLocation])
|
||||
videoBuildProcess.stderr.on('data',function(data){
|
||||
// console.log(data.toString())
|
||||
clearTimeout(completionTimeout)
|
||||
completionTimeout = setTimeout(function(){
|
||||
if(currentFile === concatFiles.length - 1){
|
||||
videoBuildProcess.kill('SIGTERM')
|
||||
}
|
||||
},4000)
|
||||
})
|
||||
videoBuildProcess.on('exit',function(data){
|
||||
var timeNow = new Date()
|
||||
var fileStats = fs.statSync(finalMp4OutputLocation)
|
||||
var details = {}
|
||||
s.sqlQuery('INSERT INTO `Files` (ke,mid,details,name,size,time) VALUES (?,?,?,?,?,?)',[ke,mid,s.s(details),finalFileName + '.mp4',fileStats.size,timeNow])
|
||||
s.setDiskUsedForGroup({ke: ke},fileStats.size / 1000000,'fileBin')
|
||||
fs.unlink(commandTempLocation,function(){
|
||||
|
||||
})
|
||||
delete(s.group[ke].activeMonitors[mid].buildingTimelapseVideo)
|
||||
})
|
||||
var readFile = function(){
|
||||
var filePath = concatFiles[currentFile]
|
||||
// console.log(filePath,currentFile,'/',concatFiles.length - 1)
|
||||
fs.readFile(filePath,function(err,buffer){
|
||||
if(!err)videoBuildProcess.stdin.write(buffer)
|
||||
if(currentFile === concatFiles.length - 1){
|
||||
//is last
|
||||
|
||||
}else{
|
||||
setTimeout(function(){
|
||||
++currentFile
|
||||
readFile()
|
||||
},1/framesPerSecond)
|
||||
}
|
||||
})
|
||||
}
|
||||
readFile()
|
||||
s.group[ke].activeMonitors[mid].buildingTimelapseVideo = videoBuildProcess
|
||||
callback({
|
||||
ok: true,
|
||||
fileExists: false,
|
||||
fileLocation: finalMp4OutputLocation,
|
||||
msg: lang['Started Building']
|
||||
})
|
||||
}else{
|
||||
callback({
|
||||
ok: false,
|
||||
fileExists: true,
|
||||
fileLocation: finalMp4OutputLocation,
|
||||
msg: lang['Already exists']
|
||||
})
|
||||
}
|
||||
}else{
|
||||
callback({
|
||||
ok: false,
|
||||
fileExists: false,
|
||||
fileLocation: finalMp4OutputLocation,
|
||||
msg: lang.Building
|
||||
})
|
||||
}
|
||||
}else{
|
||||
callback({
|
||||
ok: false,
|
||||
fileExists: false,
|
||||
msg: lang.notEnoughFramesText1
|
||||
})
|
||||
}
|
||||
}
|
||||
s.getVideoStorageIndex = function(video){
|
||||
var details = s.parseJSON(video.details) || {}
|
||||
var storageId = details.storageId
|
||||
if(s.group[video.ke] && s.group[video.ke].activeMonitors[video.id] && s.group[video.ke].activeMonitors[video.id].addStorageId)storageId = s.group[video.ke].activeMonitors[video.id].addStorageId
|
||||
if(storageId){
|
||||
return s.group[video.ke].addStorageUse[storageId]
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,6 +44,8 @@ module.exports = function(s,config,lang,io){
|
|||
if(config.renderPaths.dashcam === undefined){config.renderPaths.dashcam='pages/dashcam'}
|
||||
//embeddable widget page
|
||||
if(config.renderPaths.embed === undefined){config.renderPaths.embed='pages/embed'}
|
||||
//timelapse page (not modal)
|
||||
if(config.renderPaths.timelapse === undefined){config.renderPaths.timelapse='pages/timelapse'}
|
||||
//mjpeg full screen page
|
||||
if(config.renderPaths.mjpeg === undefined){config.renderPaths.mjpeg='pages/mjpeg'}
|
||||
//gridstack only page
|
||||
|
@ -53,6 +55,8 @@ module.exports = function(s,config,lang,io){
|
|||
// Use uws/cws
|
||||
if(config.useUWebsocketJs === undefined){config.useUWebsocketJs=true}
|
||||
//SSL options
|
||||
var wellKnownDirectory = s.mainDirectory + '/web/.well-known'
|
||||
if(fs.existsSync(wellKnownDirectory))app.use('/.well-known',express.static(wellKnownDirectory))
|
||||
if(config.ssl&&config.ssl.key&&config.ssl.cert){
|
||||
config.ssl.key=fs.readFileSync(s.checkRelativePath(config.ssl.key),'utf8')
|
||||
config.ssl.cert=fs.readFileSync(s.checkRelativePath(config.ssl.cert),'utf8')
|
||||
|
|
|
@ -68,7 +68,7 @@ module.exports = function(s,config,lang,app){
|
|||
s.closeJsonResponse(res,endData)
|
||||
return
|
||||
}
|
||||
var form = s.getPostData(req)
|
||||
var form = s.getPostData(req) || {}
|
||||
var uid = form.uid || s.getPostData(req,'uid',false)
|
||||
var mail = form.mail || s.getPostData(req,'mail',false)
|
||||
s.sqlQuery('DELETE FROM Users WHERE uid=? AND ke=? AND mail=?',[uid,req.params.ke,mail])
|
||||
|
@ -196,7 +196,7 @@ module.exports = function(s,config,lang,app){
|
|||
}
|
||||
}else{
|
||||
if(!user.details.sub || user.details.allmonitors === '1' || user.details.monitor_edit.indexOf(req.params.id) > -1 || hasRestrictions && user.details.monitor_create === '1'){
|
||||
s.userLog(s.group[req.params.ke].mon_conf[req.params.id],{type:'Monitor Deleted',msg:'by user : '+user.uid});
|
||||
s.userLog(s.group[req.params.ke].rawMonitorConfigurations[req.params.id],{type:'Monitor Deleted',msg:'by user : '+user.uid});
|
||||
req.params.delete=1;s.camera('stop',req.params);
|
||||
s.tx({f:'monitor_delete',uid:user.uid,mid:req.params.id,ke:req.params.ke},'GRP_'+req.params.ke);
|
||||
s.sqlQuery('DELETE FROM Monitors WHERE ke=? AND mid=?',[req.params.ke,req.params.id])
|
||||
|
|
|
@ -11,15 +11,16 @@ var httpProxy = require('http-proxy');
|
|||
var onvif = require('node-onvif');
|
||||
var proxy = httpProxy.createProxyServer({})
|
||||
var ejs = require('ejs');
|
||||
var CircularJSON = require('circular-json');
|
||||
module.exports = function(s,config,lang,app,io){
|
||||
if(config.productType==='Pro'){
|
||||
var LdapAuth = require('ldapauth-fork');
|
||||
}
|
||||
s.renderPage = function(req,res,paths,passables,callback){
|
||||
passables.window = {}
|
||||
passables.data = req.params
|
||||
passables.originalURL = s.getOriginalUrl(req)
|
||||
passables.config = config
|
||||
passables.baseUrl = req.protocol+'://'+req.hostname
|
||||
passables.config = s.getConfigWithBranding(req.hostname)
|
||||
res.render(paths,passables,callback)
|
||||
}
|
||||
//child node proxy check
|
||||
|
@ -28,8 +29,8 @@ module.exports = function(s,config,lang,app,io){
|
|||
//res = response, only needed for express (http server)
|
||||
//request = request, only needed for express (http server)
|
||||
s.checkChildProxy = function(params,cb,res,req){
|
||||
if(s.group[params.ke] && s.group[params.ke].mon[params.id] && s.group[params.ke].mon[params.id].childNode){
|
||||
var url = 'http://' + s.group[params.ke].mon[params.id].childNode// + req.originalUrl
|
||||
if(s.group[params.ke] && s.group[params.ke].activeMonitors[params.id] && s.group[params.ke].activeMonitors[params.id].childNode){
|
||||
var url = 'http://' + s.group[params.ke].activeMonitors[params.id].childNode// + req.originalUrl
|
||||
proxy.web(req, res, { target: url })
|
||||
}else{
|
||||
cb()
|
||||
|
@ -94,34 +95,22 @@ module.exports = function(s,config,lang,app,io){
|
|||
* Page : Login Screen
|
||||
*/
|
||||
app.get(config.webPaths.home, function (req,res){
|
||||
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'dashboard'},function(err,html){
|
||||
if(err){
|
||||
s.systemLog(err)
|
||||
}
|
||||
res.end(html)
|
||||
})
|
||||
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config: s.getConfigWithBranding(req.hostname),screen:'dashboard'})
|
||||
});
|
||||
/**
|
||||
* Page : Administrator Login Screen
|
||||
*/
|
||||
app.get(config.webPaths.admin, function (req,res){
|
||||
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'admin'},function(err,html){
|
||||
if(err){
|
||||
s.systemLog(err)
|
||||
}
|
||||
res.end(html)
|
||||
})
|
||||
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config: s.getConfigWithBranding(req.hostname),screen:'admin'})
|
||||
});
|
||||
/**
|
||||
* Page : Superuser Login Screen
|
||||
*/
|
||||
app.get(config.webPaths.super, function (req,res){
|
||||
|
||||
s.renderPage(req,res,config.renderPaths.index,{lang:lang,config:config,screen:'super'},function(err,html){
|
||||
if(err){
|
||||
s.systemLog(err)
|
||||
}
|
||||
res.end(html)
|
||||
s.renderPage(req,res,config.renderPaths.index,{
|
||||
lang: lang,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
screen: 'super'
|
||||
})
|
||||
});
|
||||
/**
|
||||
|
@ -183,13 +172,8 @@ module.exports = function(s,config,lang,app,io){
|
|||
failedLogin: true,
|
||||
message: lang.failedLoginText1,
|
||||
lang: s.copySystemDefaultLanguage(),
|
||||
config: config,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
screen: screenChooser(req.params.screen)
|
||||
},function(err,html){
|
||||
if(err){
|
||||
s.systemLog(err)
|
||||
}
|
||||
res.end(html)
|
||||
})
|
||||
}
|
||||
return false
|
||||
|
@ -207,12 +191,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
res.end(s.prettyPrint(data))
|
||||
}else{
|
||||
data.screen=req.params.screen
|
||||
s.renderPage(req,res,focus,data,function(err,html){
|
||||
if(err){
|
||||
s.systemLog(err)
|
||||
}
|
||||
res.end(html)
|
||||
})
|
||||
s.renderPage(req,res,focus,data)
|
||||
}
|
||||
}
|
||||
failedAuthentication = function(board){
|
||||
|
@ -241,13 +220,8 @@ module.exports = function(s,config,lang,app,io){
|
|||
failedLogin: true,
|
||||
message: lang.failedLoginText2,
|
||||
lang: s.copySystemDefaultLanguage(),
|
||||
config: config,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
screen: screenChooser(req.params.screen)
|
||||
},function(err,html){
|
||||
if(err){
|
||||
s.systemLog(err)
|
||||
}
|
||||
res.end(html)
|
||||
})
|
||||
}
|
||||
var logTo = {
|
||||
|
@ -284,7 +258,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
s.sqlQuery('SELECT * FROM Monitors WHERE ke=? AND type=?',[r.ke,"dashcam"],function(err,rr){
|
||||
req.resp.mons=rr;
|
||||
renderPage(config.renderPaths.dashcam,{
|
||||
// config: config,
|
||||
// config: s.getConfigWithBranding(req.hostname),
|
||||
$user: req.resp,
|
||||
lang: r.lang,
|
||||
define: s.getDefinitonFile(r.details.lang),
|
||||
|
@ -296,7 +270,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
s.sqlQuery('SELECT * FROM Monitors WHERE ke=? AND type=?',[r.ke,"socket"],function(err,rr){
|
||||
req.resp.mons=rr;
|
||||
renderPage(config.renderPaths.streamer,{
|
||||
// config: config,
|
||||
// config: s.getConfigWithBranding(req.hostname),
|
||||
$user: req.resp,
|
||||
lang: r.lang,
|
||||
define: s.getDefinitonFile(r.details.lang),
|
||||
|
@ -309,7 +283,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
s.sqlQuery('SELECT uid,mail,details FROM Users WHERE ke=? AND details LIKE \'%"sub"%\'',[r.ke],function(err,rr) {
|
||||
s.sqlQuery('SELECT * FROM Monitors WHERE ke=?',[r.ke],function(err,rrr) {
|
||||
renderPage(config.renderPaths.admin,{
|
||||
config: config,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
$user: req.resp,
|
||||
$subs: rr,
|
||||
$mons: rrr,
|
||||
|
@ -321,9 +295,13 @@ module.exports = function(s,config,lang,app,io){
|
|||
})
|
||||
}else{
|
||||
//not admin user
|
||||
renderPage(config.renderPaths.home,{
|
||||
var chosenRender = 'home'
|
||||
if(r.details.landing_page && r.details.landing_page !== '' && config.renderPaths[r.details.landing_page]){
|
||||
chosenRender = r.details.landing_page
|
||||
}
|
||||
renderPage(config.renderPaths[chosenRender],{
|
||||
$user:req.resp,
|
||||
config:config,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
lang:r.lang,
|
||||
define:s.getDefinitonFile(r.details.lang),
|
||||
addStorage:s.dir.addStorage,
|
||||
|
@ -334,16 +312,20 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
break;
|
||||
default:
|
||||
renderPage(config.renderPaths.home,{
|
||||
var chosenRender = 'home'
|
||||
if(r.details.sub && r.details.landing_page && r.details.landing_page !== '' && config.renderPaths[r.details.landing_page]){
|
||||
chosenRender = r.details.landing_page
|
||||
}
|
||||
renderPage(config.renderPaths[chosenRender],{
|
||||
$user:req.resp,
|
||||
config:config,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
lang:r.lang,
|
||||
define:s.getDefinitonFile(r.details.lang),
|
||||
addStorage:s.dir.addStorage,
|
||||
fs:fs,
|
||||
__dirname:s.mainDirectory,
|
||||
customAutoLoad: s.customAutoLoadTree
|
||||
});
|
||||
})
|
||||
break;
|
||||
}
|
||||
s.userLog({ke:r.ke,mid:'$USER'},{type:r.lang['New Authentication Token'],msg:{for:req.body.function,mail:r.mail,id:r.uid,ip:req.ip}})
|
||||
|
@ -360,6 +342,8 @@ module.exports = function(s,config,lang,app,io){
|
|||
r.details=JSON.parse(r.details);
|
||||
r.lang=s.getLanguageFile(r.details.lang)
|
||||
req.factorAuth=function(cb){
|
||||
req.params.auth = r.auth
|
||||
req.params.ke = r.ke
|
||||
if(r.details.factorAuth === "1"){
|
||||
if(!r.details.acceptedMachines||!(r.details.acceptedMachines instanceof Object)){
|
||||
r.details.acceptedMachines={}
|
||||
|
@ -494,8 +478,8 @@ module.exports = function(s,config,lang,app,io){
|
|||
req.resp.lang=r.lang
|
||||
s.sqlQuery('INSERT INTO Users (ke,uid,auth,mail,pass,details) VALUES (?,?,?,?,?,?)',user.post)
|
||||
}
|
||||
req.resp.details=JSON.stringify(req.resp.details)
|
||||
req.resp.auth_token=req.resp.auth
|
||||
req.resp.details = JSON.stringify(req.resp.details)
|
||||
req.resp.auth_token = req.resp.auth
|
||||
req.resp.ok=true
|
||||
checkRoute(req.resp)
|
||||
})
|
||||
|
@ -534,6 +518,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
data.Logs = r
|
||||
data.customAutoLoad = s.customAutoLoadTree
|
||||
data.currentVersion = s.currentVersion
|
||||
fs.readFile(s.location.config,'utf8',function(err,file){
|
||||
data.plainConfig = JSON.parse(file)
|
||||
renderPage(config.renderPaths.super,data)
|
||||
|
@ -644,8 +629,8 @@ module.exports = function(s,config,lang,app,io){
|
|||
r = filteredByGroup;
|
||||
}
|
||||
r.forEach(function(v,n){
|
||||
if(s.group[v.ke]&&s.group[v.ke].mon[v.mid]&&s.group[v.ke].mon[v.mid].watch){
|
||||
r[n].currentlyWatching=Object.keys(s.group[v.ke].mon[v.mid].watch).length
|
||||
if(s.group[v.ke]&&s.group[v.ke].activeMonitors[v.mid]&&s.group[v.ke].activeMonitors[v.mid].watch){
|
||||
r[n].currentlyWatching=Object.keys(s.group[v.ke].activeMonitors[v.mid].watch).length
|
||||
}
|
||||
r[n].subStream={}
|
||||
var details = JSON.parse(r[n].details)
|
||||
|
@ -689,7 +674,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
s.renderPage(req,res,page,{
|
||||
data:Object.assign(req.params,req.query),
|
||||
baseUrl:req.protocol+'://'+req.hostname,
|
||||
config:config,
|
||||
config: s.getConfigWithBranding(req.hostname),
|
||||
lang:user.lang,
|
||||
$user:user,
|
||||
monitors:r,
|
||||
|
@ -866,10 +851,10 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
s.sqlQuery(req.sql,req.ar,function(err,r){
|
||||
r.forEach(function(v,n){
|
||||
if(s.group[v.ke] && s.group[v.ke].mon[v.mid]){
|
||||
r[n].currentlyWatching = Object.keys(s.group[v.ke].mon[v.mid].watch).length
|
||||
r[n].currentCpuUsage = s.group[v.ke].mon[v.mid].currentCpuUsage
|
||||
r[n].status = s.group[v.ke].mon[v.mid].monitorStatus
|
||||
if(s.group[v.ke] && s.group[v.ke].activeMonitors[v.mid]){
|
||||
r[n].currentlyWatching = Object.keys(s.group[v.ke].activeMonitors[v.mid].watch).length
|
||||
r[n].currentCpuUsage = s.group[v.ke].activeMonitors[v.mid].currentCpuUsage
|
||||
r[n].status = s.group[v.ke].activeMonitors[v.mid].monitorStatus
|
||||
}
|
||||
var buildStreamURL = function(type,channelNumber){
|
||||
var streamURL
|
||||
|
@ -909,7 +894,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
r[n].streamsSortedByType={}
|
||||
buildStreamURL(details.stream_type)
|
||||
if(details.stream_channels&&details.stream_channels!==''){
|
||||
details.stream_channels=JSON.parse(details.stream_channels)
|
||||
details.stream_channels=s.parseJSON(details.stream_channels)
|
||||
details.stream_channels.forEach(function(b,m){
|
||||
buildStreamURL(b.stream_type,m.toString())
|
||||
})
|
||||
|
@ -1096,7 +1081,10 @@ module.exports = function(s,config,lang,app,io){
|
|||
/**
|
||||
* API : Get Events
|
||||
*/
|
||||
app.get([config.webPaths.apiPrefix+':auth/events/:ke',config.webPaths.apiPrefix+':auth/events/:ke/:id',config.webPaths.apiPrefix+':auth/events/:ke/:id/:limit',config.webPaths.apiPrefix+':auth/events/:ke/:id/:limit/:start',config.webPaths.apiPrefix+':auth/events/:ke/:id/:limit/:start/:end'], function (req,res){
|
||||
app.get([
|
||||
config.webPaths.apiPrefix+':auth/events/:ke',
|
||||
config.webPaths.apiPrefix+':auth/events/:ke/:id'
|
||||
], function (req,res){
|
||||
req.ret={ok:false};
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
s.auth(req.params,function(user){
|
||||
|
@ -1122,20 +1110,42 @@ module.exports = function(s,config,lang,app,io){
|
|||
return;
|
||||
}
|
||||
}
|
||||
if(req.params.start&&req.params.start!==''){
|
||||
req.params.start = s.stringToSqlTime(req.params.start)
|
||||
if(req.params.end&&req.params.end!==''){
|
||||
req.params.end = s.stringToSqlTime(req.params.end)
|
||||
req.sql+=' AND `time` >= ? AND `time` <= ?';
|
||||
req.ar.push(decodeURIComponent(req.params.start))
|
||||
req.ar.push(decodeURIComponent(req.params.end))
|
||||
}else{
|
||||
req.sql+=' AND `time` >= ?';
|
||||
req.ar.push(decodeURIComponent(req.params.start))
|
||||
if(req.query.start||req.query.end){
|
||||
if(req.query.start && req.query.start !== ''){
|
||||
req.query.start = s.stringToSqlTime(req.query.start)
|
||||
}
|
||||
if(req.query.end && req.query.end !== ''){
|
||||
req.query.end = s.stringToSqlTime(req.query.end)
|
||||
}
|
||||
if(!req.query.startOperator||req.query.startOperator==''){
|
||||
req.query.startOperator='>='
|
||||
}
|
||||
if(!req.query.endOperator||req.query.endOperator==''){
|
||||
req.query.endOperator='<='
|
||||
}
|
||||
switch(true){
|
||||
case(req.query.start&&req.query.start!==''&&req.query.end&&req.query.end!==''):
|
||||
req.sql+=' AND `time` '+req.query.startOperator+' ? AND `time` '+req.query.endOperator+' ?';
|
||||
req.ar.push(req.query.start)
|
||||
req.ar.push(req.query.end)
|
||||
break;
|
||||
case(req.query.start&&req.query.start!==''):
|
||||
req.sql+=' AND `time` '+req.query.startOperator+' ?';
|
||||
req.ar.push(req.query.start)
|
||||
break;
|
||||
case(req.query.end&&req.query.end!==''):
|
||||
req.sql+=' AND `time` '+req.query.endOperator+' ?';
|
||||
req.ar.push(req.query.end)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!req.params.limit||req.params.limit==''){req.params.limit=100}
|
||||
req.sql+=' ORDER BY `time` DESC LIMIT '+req.params.limit+'';
|
||||
req.sql+=' ORDER BY `time` DESC';
|
||||
if(!req.query.limit||req.query.limit==''){
|
||||
req.query.limit='100'
|
||||
}
|
||||
if(req.query.limit!=='0'){
|
||||
req.sql+=' LIMIT '+req.query.limit
|
||||
}
|
||||
s.sqlQuery(req.sql,req.ar,function(err,r){
|
||||
if(err){
|
||||
err.sql=req.sql;
|
||||
|
@ -1238,7 +1248,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
if(r&&r[0]){
|
||||
req.ar=[];
|
||||
r.forEach(function(v){
|
||||
if(s.group[req.params.ke]&&s.group[req.params.ke].mon[v.mid]&&s.group[req.params.ke].mon[v.mid].isStarted === true){
|
||||
if(s.group[req.params.ke]&&s.group[req.params.ke].activeMonitors[v.mid]&&s.group[req.params.ke].activeMonitors[v.mid].isStarted === true){
|
||||
req.ar.push(v)
|
||||
}
|
||||
})
|
||||
|
@ -1270,25 +1280,25 @@ module.exports = function(s,config,lang,app,io){
|
|||
s.sqlQuery('SELECT * FROM Monitors WHERE ke=? AND mid=?',[req.params.ke,req.params.id],function(err,r){
|
||||
if(r&&r[0]){
|
||||
r=r[0];
|
||||
if(req.query.reset==='1'||(s.group[r.ke]&&s.group[r.ke].mon_conf[r.mid].mode!==req.params.f)||req.query.fps&&(!s.group[r.ke].mon[r.mid].currentState||!s.group[r.ke].mon[r.mid].currentState.trigger_on)){
|
||||
if(req.query.reset!=='1'||!s.group[r.ke].mon[r.mid].trigger_timer){
|
||||
if(!s.group[r.ke].mon[r.mid].currentState)s.group[r.ke].mon[r.mid].currentState={}
|
||||
s.group[r.ke].mon[r.mid].currentState.mode=r.mode.toString()
|
||||
s.group[r.ke].mon[r.mid].currentState.fps=r.fps.toString()
|
||||
if(!s.group[r.ke].mon[r.mid].currentState.trigger_on){
|
||||
s.group[r.ke].mon[r.mid].currentState.trigger_on=true
|
||||
if(req.query.reset==='1'||(s.group[r.ke]&&s.group[r.ke].rawMonitorConfigurations[r.mid].mode!==req.params.f)||req.query.fps&&(!s.group[r.ke].activeMonitors[r.mid].currentState||!s.group[r.ke].activeMonitors[r.mid].currentState.trigger_on)){
|
||||
if(req.query.reset!=='1'||!s.group[r.ke].activeMonitors[r.mid].trigger_timer){
|
||||
if(!s.group[r.ke].activeMonitors[r.mid].currentState)s.group[r.ke].activeMonitors[r.mid].currentState={}
|
||||
s.group[r.ke].activeMonitors[r.mid].currentState.mode=r.mode.toString()
|
||||
s.group[r.ke].activeMonitors[r.mid].currentState.fps=r.fps.toString()
|
||||
if(!s.group[r.ke].activeMonitors[r.mid].currentState.trigger_on){
|
||||
s.group[r.ke].activeMonitors[r.mid].currentState.trigger_on=true
|
||||
}else{
|
||||
s.group[r.ke].mon[r.mid].currentState.trigger_on=false
|
||||
s.group[r.ke].activeMonitors[r.mid].currentState.trigger_on=false
|
||||
}
|
||||
r.mode=req.params.f;
|
||||
try{r.details=JSON.parse(r.details);}catch(er){}
|
||||
if(req.query.fps){
|
||||
r.fps=parseFloat(r.details.detector_trigger_record_fps)
|
||||
s.group[r.ke].mon[r.mid].currentState.detector_trigger_record_fps=r.fps
|
||||
s.group[r.ke].activeMonitors[r.mid].currentState.detector_trigger_record_fps=r.fps
|
||||
}
|
||||
r.id=r.mid;
|
||||
s.sqlQuery('UPDATE Monitors SET mode=? WHERE ke=? AND mid=?',[r.mode,r.ke,r.mid]);
|
||||
s.group[r.ke].mon_conf[r.mid]=r;
|
||||
s.group[r.ke].rawMonitorConfigurations[r.mid]=r;
|
||||
s.tx({f:'monitor_edit',mid:r.mid,ke:r.ke,mon:r},'GRP_'+r.ke);
|
||||
s.tx({f:'monitor_edit',mid:r.mid,ke:r.ke,mon:r},'STR_'+r.ke);
|
||||
s.camera('stop',s.cleanMonitorObject(r));
|
||||
|
@ -1303,7 +1313,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
req.ret.ok=true;
|
||||
if(req.params.ff&&req.params.f!=='stop'){
|
||||
req.params.ff=parseFloat(req.params.ff);
|
||||
clearTimeout(s.group[r.ke].mon[r.mid].trigger_timer)
|
||||
clearTimeout(s.group[r.ke].activeMonitors[r.mid].trigger_timer)
|
||||
switch(req.params.fff){
|
||||
case'day':case'days':
|
||||
req.timeout=req.params.ff*1000*60*60*24
|
||||
|
@ -1318,17 +1328,17 @@ module.exports = function(s,config,lang,app,io){
|
|||
req.timeout=req.params.ff*1000
|
||||
break;
|
||||
}
|
||||
s.group[r.ke].mon[r.mid].trigger_timer=setTimeout(function(){
|
||||
delete(s.group[r.ke].mon[r.mid].trigger_timer)
|
||||
s.sqlQuery('UPDATE Monitors SET mode=? WHERE ke=? AND mid=?',[s.group[r.ke].mon[r.mid].currentState.mode,r.ke,r.mid]);
|
||||
s.group[r.ke].activeMonitors[r.mid].trigger_timer=setTimeout(function(){
|
||||
delete(s.group[r.ke].activeMonitors[r.mid].trigger_timer)
|
||||
s.sqlQuery('UPDATE Monitors SET mode=? WHERE ke=? AND mid=?',[s.group[r.ke].activeMonitors[r.mid].currentState.mode,r.ke,r.mid]);
|
||||
r.neglectTriggerTimer=1;
|
||||
r.mode=s.group[r.ke].mon[r.mid].currentState.mode;
|
||||
r.fps=s.group[r.ke].mon[r.mid].currentState.fps;
|
||||
r.mode=s.group[r.ke].activeMonitors[r.mid].currentState.mode;
|
||||
r.fps=s.group[r.ke].activeMonitors[r.mid].currentState.fps;
|
||||
s.camera('stop',s.cleanMonitorObject(r),function(){
|
||||
if(s.group[r.ke].mon[r.mid].currentState.mode!=='stop'){
|
||||
s.camera(s.group[r.ke].mon[r.mid].currentState.mode,s.cleanMonitorObject(r));
|
||||
if(s.group[r.ke].activeMonitors[r.mid].currentState.mode!=='stop'){
|
||||
s.camera(s.group[r.ke].activeMonitors[r.mid].currentState.mode,s.cleanMonitorObject(r));
|
||||
}
|
||||
s.group[r.ke].mon_conf[r.mid]=r;
|
||||
s.group[r.ke].rawMonitorConfigurations[r.mid]=r;
|
||||
});
|
||||
s.tx({f:'monitor_edit',mid:r.mid,ke:r.ke,mon:r},'GRP_'+r.ke);
|
||||
s.tx({f:'monitor_edit',mid:r.mid,ke:r.ke,mon:r},'STR_'+r.ke);
|
||||
|
@ -1382,31 +1392,32 @@ module.exports = function(s,config,lang,app,io){
|
|||
* API : Get fileBin file
|
||||
*/
|
||||
app.get(config.webPaths.apiPrefix+':auth/fileBin/:ke/:id/:year/:month/:day/:file', function (req,res){
|
||||
req.fn=function(user){
|
||||
req.failed=function(){
|
||||
s.auth(req.params,function(user){
|
||||
var failed = function(){
|
||||
res.end(user.lang['File Not Found'])
|
||||
}
|
||||
if (!s.group[req.params.ke].fileBin[req.params.id+'/'+req.params.file]){
|
||||
s.sqlQuery('SELECT * FROM Files WHERE ke=? AND mid=? AND name=?',[req.params.ke,req.params.id,req.params.file],function(err,r){
|
||||
if(r&&r[0]){
|
||||
r=r[0]
|
||||
r.details=JSON.parse(r.details)
|
||||
req.dir=s.dir.fileBin+req.params.ke+'/'+req.params.id+'/'+r.details.year+'/'+r.details.month+'/'+r.details.day+'/'+req.params.file;
|
||||
if(fs.existsSync(req.dir)){
|
||||
res.on('finish',function(){res.end();});
|
||||
fs.createReadStream(req.dir).pipe(res);
|
||||
}else{
|
||||
req.failed()
|
||||
}
|
||||
r = r[0]
|
||||
r.details = JSON.parse(r.details)
|
||||
req.dir = s.dir.fileBin+req.params.ke+'/'+req.params.id+'/'+r.details.year+'/'+r.details.month+'/'+r.details.day+'/'+req.params.file;
|
||||
fs.stat(req.dir,function(err,stats){
|
||||
if(!err){
|
||||
res.on('finish',function(){res.end()})
|
||||
fs.createReadStream(req.dir).pipe(res)
|
||||
}else{
|
||||
failed()
|
||||
}
|
||||
})
|
||||
}else{
|
||||
req.failed()
|
||||
failed()
|
||||
}
|
||||
})
|
||||
}else{
|
||||
res.end(user.lang['Please Wait for Completion'])
|
||||
}
|
||||
}
|
||||
s.auth(req.params,req.fn,res,req);
|
||||
},res,req);
|
||||
});
|
||||
/**
|
||||
* API : Zip Videos and Get Link from fileBin
|
||||
|
@ -1451,52 +1462,52 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
fs.unlink(zippedFile);
|
||||
})
|
||||
if(!fs.existsSync(fileBinDir)){
|
||||
fs.mkdirSync(fileBinDir);
|
||||
}
|
||||
r.forEach(function(video){
|
||||
var timeFormatted = s.formattedTime(video.time)
|
||||
video.filename = timeFormatted+'.'+video.ext
|
||||
var dir = s.getVideoDirectory(video)+video.filename
|
||||
var tempVideoFile = timeFormatted+' - '+video.mid+'.'+video.ext
|
||||
fs.writeFileSync(fileBinDir+tempVideoFile, fs.readFileSync(dir))
|
||||
tempFiles.push(fileBinDir+tempVideoFile)
|
||||
script += ' "'+tempVideoFile+'"'
|
||||
})
|
||||
fs.writeFileSync(tempScript,script,'utf8')
|
||||
var zipCreate = spawn('sh',(tempScript).split(' '),{detached: true})
|
||||
zipCreate.stderr.on('data',function(data){
|
||||
s.userLog({ke:req.params.ke,mid:'$USER'},{title:'Zip Create Error',msg:data.toString()})
|
||||
})
|
||||
zipCreate.on('exit',function(data){
|
||||
fs.unlinkSync(tempScript)
|
||||
tempFiles.forEach(function(file){
|
||||
fs.unlink(file,function(){})
|
||||
fs.mkdir(fileBinDir,function(err){
|
||||
s.handleFolderError(err)
|
||||
r.forEach(function(video){
|
||||
var timeFormatted = s.formattedTime(video.time)
|
||||
video.filename = timeFormatted+'.'+video.ext
|
||||
var dir = s.getVideoDirectory(video)+video.filename
|
||||
var tempVideoFile = timeFormatted+' - '+video.mid+'.'+video.ext
|
||||
fs.writeFileSync(fileBinDir+tempVideoFile, fs.readFileSync(dir))
|
||||
tempFiles.push(fileBinDir+tempVideoFile)
|
||||
script += ' "'+tempVideoFile+'"'
|
||||
})
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="'+zippedFilename+'"')
|
||||
var zipDownload = fs.createReadStream(zippedFile)
|
||||
zipDownload.pipe(res)
|
||||
zipDownload.on('error', function (error) {
|
||||
var errorString = error.toString()
|
||||
s.userLog({
|
||||
ke: req.params.ke,
|
||||
mid: '$USER'
|
||||
},{
|
||||
title: 'Zip Download Error',
|
||||
msg: errorString
|
||||
fs.writeFileSync(tempScript,script,'utf8')
|
||||
var zipCreate = spawn('sh',(tempScript).split(' '),{detached: true})
|
||||
zipCreate.stderr.on('data',function(data){
|
||||
s.userLog({ke:req.params.ke,mid:'$USER'},{title:'Zip Create Error',msg:data.toString()})
|
||||
})
|
||||
zipCreate.on('exit',function(data){
|
||||
fs.unlinkSync(tempScript)
|
||||
tempFiles.forEach(function(file){
|
||||
fs.unlink(file,function(){})
|
||||
})
|
||||
if(zipDownload && zipDownload.destroy){
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="'+zippedFilename+'"')
|
||||
var zipDownload = fs.createReadStream(zippedFile)
|
||||
zipDownload.pipe(res)
|
||||
zipDownload.on('error', function (error) {
|
||||
var errorString = error.toString()
|
||||
s.userLog({
|
||||
ke: req.params.ke,
|
||||
mid: '$USER'
|
||||
},{
|
||||
title: 'Zip Download Error',
|
||||
msg: errorString
|
||||
})
|
||||
if(zipDownload && zipDownload.destroy){
|
||||
zipDownload.destroy()
|
||||
}
|
||||
res.end(s.prettyPrint({
|
||||
ok: false,
|
||||
msg: errorString
|
||||
}))
|
||||
})
|
||||
zipDownload.on('close', function () {
|
||||
res.end()
|
||||
zipDownload.destroy()
|
||||
}
|
||||
res.end(s.prettyPrint({
|
||||
ok: false,
|
||||
msg: errorString
|
||||
}))
|
||||
})
|
||||
zipDownload.on('close', function () {
|
||||
res.end()
|
||||
zipDownload.destroy()
|
||||
fs.unlinkSync(zippedFile)
|
||||
fs.unlinkSync(zippedFile)
|
||||
})
|
||||
})
|
||||
})
|
||||
}else{
|
||||
|
@ -1551,64 +1562,63 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
fs.unlink(zippedFile);
|
||||
})
|
||||
if(!fs.existsSync(fileBinDir)){
|
||||
fs.mkdirSync(fileBinDir);
|
||||
}
|
||||
var cloudDownloadCount = 0
|
||||
var getFile = function(video,completed){
|
||||
if(!video)completed();
|
||||
s.checkDetails(video)
|
||||
var filename = video.href.split('/')
|
||||
filename = filename[filename.length - 1]
|
||||
var timeFormatted = s.formattedTime(video.time)
|
||||
var tempVideoFile = video.details.type + '-' + video.mid + '-' + filename
|
||||
var tempFileWriteStream = fs.createWriteStream(fileBinDir+tempVideoFile)
|
||||
tempFileWriteStream.on('finish', function() {
|
||||
++cloudDownloadCount
|
||||
getFile(r[cloudDownloadCount],completed)
|
||||
})
|
||||
var cloudVideoDownload = request(video.href)
|
||||
cloudVideoDownload.on('response', function (res) {
|
||||
res.pipe(tempFileWriteStream)
|
||||
})
|
||||
tempFiles.push(fileBinDir+tempVideoFile)
|
||||
script += ' "'+tempVideoFile+'"'
|
||||
}
|
||||
getFile(r[cloudDownloadCount],function(){
|
||||
fs.writeFileSync(tempScript,script,'utf8')
|
||||
var zipCreate = spawn('sh',(tempScript).split(' '),{detached: true})
|
||||
zipCreate.stderr.on('data',function(data){
|
||||
s.userLog({ke:req.params.ke,mid:'$USER'},{title:'Zip Create Error',msg:data.toString()})
|
||||
})
|
||||
zipCreate.on('exit',function(data){
|
||||
fs.unlinkSync(tempScript)
|
||||
tempFiles.forEach(function(file){
|
||||
fs.unlink(file,function(){})
|
||||
fs.mkdir(fileBinDir,function(err){
|
||||
var cloudDownloadCount = 0
|
||||
var getFile = function(video,completed){
|
||||
if(!video)completed();
|
||||
s.checkDetails(video)
|
||||
var filename = video.href.split('/')
|
||||
filename = filename[filename.length - 1]
|
||||
var timeFormatted = s.formattedTime(video.time)
|
||||
var tempVideoFile = video.details.type + '-' + video.mid + '-' + filename
|
||||
var tempFileWriteStream = fs.createWriteStream(fileBinDir+tempVideoFile)
|
||||
tempFileWriteStream.on('finish', function() {
|
||||
++cloudDownloadCount
|
||||
getFile(r[cloudDownloadCount],completed)
|
||||
})
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="' + zippedFilename + '"')
|
||||
var zipDownload = fs.createReadStream(zippedFile)
|
||||
zipDownload.pipe(res)
|
||||
zipDownload.on('error', function (error) {
|
||||
var errorString = error.toString()
|
||||
s.userLog({
|
||||
ke: req.params.ke,
|
||||
mid: '$USER'
|
||||
},{
|
||||
title: 'Zip Download Error',
|
||||
msg: errorString
|
||||
var cloudVideoDownload = request(video.href)
|
||||
cloudVideoDownload.on('response', function (res) {
|
||||
res.pipe(tempFileWriteStream)
|
||||
})
|
||||
tempFiles.push(fileBinDir+tempVideoFile)
|
||||
script += ' "'+tempVideoFile+'"'
|
||||
}
|
||||
getFile(r[cloudDownloadCount],function(){
|
||||
fs.writeFileSync(tempScript,script,'utf8')
|
||||
var zipCreate = spawn('sh',(tempScript).split(' '),{detached: true})
|
||||
zipCreate.stderr.on('data',function(data){
|
||||
s.userLog({ke:req.params.ke,mid:'$USER'},{title:'Zip Create Error',msg:data.toString()})
|
||||
})
|
||||
zipCreate.on('exit',function(data){
|
||||
fs.unlinkSync(tempScript)
|
||||
tempFiles.forEach(function(file){
|
||||
fs.unlink(file,function(){})
|
||||
})
|
||||
if(zipDownload && zipDownload.destroy){
|
||||
res.setHeader('Content-Disposition', 'attachment; filename="' + zippedFilename + '"')
|
||||
var zipDownload = fs.createReadStream(zippedFile)
|
||||
zipDownload.pipe(res)
|
||||
zipDownload.on('error', function (error) {
|
||||
var errorString = error.toString()
|
||||
s.userLog({
|
||||
ke: req.params.ke,
|
||||
mid: '$USER'
|
||||
},{
|
||||
title: 'Zip Download Error',
|
||||
msg: errorString
|
||||
})
|
||||
if(zipDownload && zipDownload.destroy){
|
||||
zipDownload.destroy()
|
||||
}
|
||||
res.end(s.prettyPrint({
|
||||
ok: false,
|
||||
msg: errorString
|
||||
}))
|
||||
})
|
||||
zipDownload.on('close', function () {
|
||||
res.end()
|
||||
zipDownload.destroy()
|
||||
}
|
||||
res.end(s.prettyPrint({
|
||||
ok: false,
|
||||
msg: errorString
|
||||
}))
|
||||
})
|
||||
zipDownload.on('close', function () {
|
||||
res.end()
|
||||
zipDownload.destroy()
|
||||
fs.unlinkSync(zippedFile)
|
||||
fs.unlinkSync(zippedFile)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
@ -1662,11 +1672,13 @@ module.exports = function(s,config,lang,app,io){
|
|||
s.sqlQuery('SELECT * FROM Videos WHERE ke=? AND mid=? AND `time`=? LIMIT 1',[req.params.ke,req.params.id,time],function(err,r){
|
||||
if(r&&r[0]){
|
||||
req.dir=s.getVideoDirectory(r[0])+req.params.file
|
||||
if (fs.existsSync(req.dir)){
|
||||
s.streamMp4FileOverHttp(req.dir,req,res)
|
||||
}else{
|
||||
res.end(user.lang['File Not Found in Filesystem'])
|
||||
}
|
||||
fs.stat(req.dir,function(err,stats){
|
||||
if (!err){
|
||||
s.streamMp4FileOverHttp(req.dir,req,res)
|
||||
}else{
|
||||
res.end(user.lang['File Not Found in Filesystem'])
|
||||
}
|
||||
})
|
||||
}else{
|
||||
res.end(user.lang['File Not Found in Database'])
|
||||
}
|
||||
|
@ -1678,30 +1690,76 @@ module.exports = function(s,config,lang,app,io){
|
|||
*/
|
||||
app.get(config.webPaths.apiPrefix+':auth/motion/:ke/:id', function (req,res){
|
||||
s.auth(req.params,function(user){
|
||||
var endData = {
|
||||
|
||||
}
|
||||
if(req.query.data){
|
||||
try{
|
||||
var d = {
|
||||
id: req.params.id,
|
||||
ke: req.params.ke,
|
||||
details: JSON.parse(req.query.data)
|
||||
details: s.parseJSON(req.query.data)
|
||||
}
|
||||
}catch(err){
|
||||
res.end('Data Broken',err)
|
||||
s.closeJsonResponse(res,{
|
||||
ok: false,
|
||||
msg: user.lang['Data Broken']
|
||||
})
|
||||
return
|
||||
}
|
||||
}else{
|
||||
res.end('No Data')
|
||||
s.closeJsonResponse(res,{
|
||||
ok: false,
|
||||
msg: user.lang['No Data']
|
||||
})
|
||||
return
|
||||
}
|
||||
if(!d.ke||!d.id||!s.group[d.ke]){
|
||||
res.end(user.lang['No Group with this key exists'])
|
||||
s.closeJsonResponse(res,{
|
||||
ok: false,
|
||||
msg: user.lang['No Group with this key exists']
|
||||
})
|
||||
return
|
||||
}
|
||||
if(!s.group[d.ke].rawMonitorConfigurations[d.id]){
|
||||
s.closeJsonResponse(res,{
|
||||
ok: false,
|
||||
msg: user.lang['Monitor or Key does not exist.']
|
||||
})
|
||||
return
|
||||
}
|
||||
var details = s.group[d.ke].rawMonitorConfigurations[d.id].details
|
||||
var detectorHttpApi = details.detector_http_api
|
||||
var detectorOn = (details.detector === '1')
|
||||
switch(detectorHttpApi){
|
||||
case'0':
|
||||
s.closeJsonResponse(res,{
|
||||
ok: false,
|
||||
msg: user.lang['Trigger Blocked']
|
||||
})
|
||||
return
|
||||
break;
|
||||
case'2':
|
||||
if(!detectorOn){
|
||||
s.closeJsonResponse(res,{
|
||||
ok: false,
|
||||
msg: user.lang['Trigger Blocked']
|
||||
})
|
||||
return
|
||||
}
|
||||
break;
|
||||
case'2':
|
||||
if(detectorOn){
|
||||
s.closeJsonResponse(res,{
|
||||
ok: false,
|
||||
msg: user.lang['Trigger Blocked']
|
||||
})
|
||||
return
|
||||
}
|
||||
break;
|
||||
}
|
||||
s.triggerEvent(d)
|
||||
res.end(user.lang['Trigger Successful'])
|
||||
s.closeJsonResponse(res,{
|
||||
ok: true,
|
||||
msg: user.lang['Trigger Successful']
|
||||
})
|
||||
},res,req)
|
||||
})
|
||||
/**
|
||||
|
@ -1809,13 +1867,13 @@ module.exports = function(s,config,lang,app,io){
|
|||
var checkOrigin = function(search){return req.headers.host.indexOf(search)>-1}
|
||||
if(checkOrigin('127.0.0.1')){
|
||||
if(!req.params.feed){req.params.feed='1'}
|
||||
if(!s.group[req.params.ke].mon[req.params.id].streamIn[req.params.feed]){
|
||||
s.group[req.params.ke].mon[req.params.id].streamIn[req.params.feed] = new events.EventEmitter().setMaxListeners(0)
|
||||
if(!s.group[req.params.ke].activeMonitors[req.params.id].streamIn[req.params.feed]){
|
||||
s.group[req.params.ke].activeMonitors[req.params.id].streamIn[req.params.feed] = new events.EventEmitter().setMaxListeners(0)
|
||||
}
|
||||
//req.params.feed = Feed Number
|
||||
res.connection.setTimeout(0);
|
||||
req.on('data', function(buffer){
|
||||
s.group[req.params.ke].mon[req.params.id].streamIn[req.params.feed].emit('data',buffer)
|
||||
s.group[req.params.ke].activeMonitors[req.params.id].streamIn[req.params.feed].emit('data',buffer)
|
||||
});
|
||||
req.on('end',function(){
|
||||
// console.log('streamIn closed',req.params);
|
||||
|
@ -1873,7 +1931,10 @@ module.exports = function(s,config,lang,app,io){
|
|||
/**
|
||||
* API : ONVIF Method Controller
|
||||
*/
|
||||
app.all([config.webPaths.apiPrefix+':auth/onvif/:ke/:id/:action',config.webPaths.apiPrefix+':auth/onvif/:ke/:id/:service/:action'],function (req,res){
|
||||
app.all([
|
||||
config.webPaths.apiPrefix+':auth/onvif/:ke/:id/:action',
|
||||
config.webPaths.apiPrefix+':auth/onvif/:ke/:id/:service/:action'
|
||||
],function (req,res){
|
||||
var response = {ok:false};
|
||||
res.setHeader('Content-Type', 'application/json');
|
||||
s.auth(req.params,function(user){
|
||||
|
@ -1904,7 +1965,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
var completeAction = function(command){
|
||||
if(command.then){
|
||||
command.then(actionCallback).catch(function(error){
|
||||
errorMessage('Device responded with an error',error)
|
||||
errorMessage('Device Action responded with an error',error)
|
||||
})
|
||||
}else if(command){
|
||||
response.ok = true
|
||||
|
@ -1927,6 +1988,7 @@ module.exports = function(s,config,lang,app,io){
|
|||
}else{
|
||||
action = Camera[req.params.action]
|
||||
}
|
||||
console.log(s.parseJSON(req.query.options))
|
||||
if(!action || typeof action !== 'function'){
|
||||
errorMessage(req.params.action+' is not an available ONVIF function. See https://github.com/futomi/node-onvif for functions.')
|
||||
}else{
|
||||
|
@ -1970,10 +2032,10 @@ module.exports = function(s,config,lang,app,io){
|
|||
completeAction(command)
|
||||
}
|
||||
}
|
||||
if(!s.group[req.params.ke].mon[req.params.id].onvifConnection){
|
||||
if(!s.group[req.params.ke].activeMonitors[req.params.id].onvifConnection){
|
||||
//prepeare onvif connection
|
||||
var controlURL
|
||||
var monitorConfig = s.group[req.params.ke].mon_conf[req.params.id]
|
||||
var monitorConfig = s.group[req.params.ke].rawMonitorConfigurations[req.params.id]
|
||||
if(!monitorConfig.details.control_base_url||monitorConfig.details.control_base_url===''){
|
||||
controlURL = s.buildMonitorUrl(monitorConfig, true)
|
||||
}else{
|
||||
|
@ -1981,19 +2043,19 @@ module.exports = function(s,config,lang,app,io){
|
|||
}
|
||||
var controlURLOptions = s.cameraControlOptionsFromUrl(controlURL,monitorConfig)
|
||||
//create onvif connection
|
||||
s.group[req.params.ke].mon[req.params.id].onvifConnection = new onvif.OnvifDevice({
|
||||
s.group[req.params.ke].activeMonitors[req.params.id].onvifConnection = new onvif.OnvifDevice({
|
||||
xaddr : 'http://' + controlURLOptions.host + ':' + controlURLOptions.port + '/onvif/device_service',
|
||||
user : controlURLOptions.username,
|
||||
pass : controlURLOptions.password
|
||||
})
|
||||
var device = s.group[req.params.ke].mon[req.params.id].onvifConnection
|
||||
var device = s.group[req.params.ke].activeMonitors[req.params.id].onvifConnection
|
||||
device.init().then((info) => {
|
||||
if(info)doAction(device)
|
||||
}).catch(function(error){
|
||||
return errorMessage('Device responded with an error',error)
|
||||
})
|
||||
}else{
|
||||
doAction(s.group[req.params.ke].mon[req.params.id].onvifConnection)
|
||||
doAction(s.group[req.params.ke].activeMonitors[req.params.id].onvifConnection)
|
||||
}
|
||||
},res,req);
|
||||
})
|
||||
|
@ -2021,6 +2083,30 @@ module.exports = function(s,config,lang,app,io){
|
|||
},res,req)
|
||||
})
|
||||
/**
|
||||
* API : Get Definitions JSON
|
||||
*/
|
||||
app.get(config.webPaths.apiPrefix+':auth/definitions/:ke',function (req,res){
|
||||
s.auth(req.params,function(user){
|
||||
var endData = {
|
||||
ok: true,
|
||||
definitions: s.getDefinitonFile(user.details.lang)
|
||||
}
|
||||
s.closeJsonResponse(res,endData)
|
||||
},res,req)
|
||||
})
|
||||
/**
|
||||
* API : Get Language JSON
|
||||
*/
|
||||
app.get(config.webPaths.apiPrefix+':auth/language/:ke',function (req,res){
|
||||
s.auth(req.params,function(user){
|
||||
var endData = {
|
||||
ok: true,
|
||||
definitions: s.getLanguageFile(user.details.lang)
|
||||
}
|
||||
s.closeJsonResponse(res,endData)
|
||||
},res,req)
|
||||
})
|
||||
/**
|
||||
* Robots.txt
|
||||
*/
|
||||
app.get('/robots.txt', function (req,res){
|
||||
|
|
|
@ -10,7 +10,6 @@ var spawn = require('child_process').spawn;
|
|||
var httpProxy = require('http-proxy');
|
||||
var proxy = httpProxy.createProxyServer({})
|
||||
var ejs = require('ejs');
|
||||
var CircularJSON = require('circular-json');
|
||||
module.exports = function(s,config,lang,app){
|
||||
/**
|
||||
* Page : Get Embed Stream
|
||||
|
@ -22,10 +21,10 @@ module.exports = function(s,config,lang,app){
|
|||
res.end(user.lang['Not Permitted'])
|
||||
return
|
||||
}
|
||||
if(s.group[req.params.ke]&&s.group[req.params.ke].mon[req.params.id]){
|
||||
if(s.group[req.params.ke].mon[req.params.id].isStarted === true){
|
||||
if(s.group[req.params.ke]&&s.group[req.params.ke].activeMonitors[req.params.id]){
|
||||
if(s.group[req.params.ke].activeMonitors[req.params.id].isStarted === true){
|
||||
req.params.uid=user.uid;
|
||||
s.renderPage(req,res,config.renderPaths.embed,{data:req.params,baseUrl:req.protocol+'://'+req.hostname,config:config,lang:user.lang,mon:CircularJSON.parse(CircularJSON.stringify(s.group[req.params.ke].mon_conf[req.params.id])),originalURL:s.getOriginalUrl(req)});
|
||||
s.renderPage(req,res,config.renderPaths.embed,{data:req.params,baseUrl:req.protocol+'://'+req.hostname,config: s.getConfigWithBranding(req.hostname),lang:user.lang,mon:CircularJSON.parse(CircularJSON.stringify(s.group[req.params.ke].rawMonitorConfigurations[req.params.id])),originalURL:s.getOriginalUrl(req)});
|
||||
res.end()
|
||||
}else{
|
||||
res.end(user.lang['Cannot watch a monitor that isn\'t running.'])
|
||||
|
@ -40,7 +39,7 @@ module.exports = function(s,config,lang,app){
|
|||
*/
|
||||
app.get([config.webPaths.apiPrefix+':auth/mp4/:ke/:id/:channel/s.mp4',config.webPaths.apiPrefix+':auth/mp4/:ke/:id/s.mp4',config.webPaths.apiPrefix+':auth/mp4/:ke/:id/:channel/s.ts',config.webPaths.apiPrefix+':auth/mp4/:ke/:id/s.ts'], function (req, res) {
|
||||
s.auth(req.params,function(user){
|
||||
if(!s.group[req.params.ke] || !s.group[req.params.ke].mon[req.params.id]){
|
||||
if(!s.group[req.params.ke] || !s.group[req.params.ke].activeMonitors[req.params.id]){
|
||||
res.status(404);
|
||||
res.end('404 : Monitor not found');
|
||||
return
|
||||
|
@ -50,7 +49,7 @@ module.exports = function(s,config,lang,app){
|
|||
if(req.params.channel){
|
||||
Channel = parseInt(req.params.channel)+config.pipeAddition
|
||||
}
|
||||
var mp4frag = s.group[req.params.ke].mon[req.params.id].mp4frag[Channel];
|
||||
var mp4frag = s.group[req.params.ke].activeMonitors[req.params.id].mp4frag[Channel];
|
||||
var errorMessage = 'MP4 Stream is not enabled'
|
||||
if(!mp4frag){
|
||||
res.status(503);
|
||||
|
@ -105,7 +104,7 @@ module.exports = function(s,config,lang,app){
|
|||
}else{
|
||||
s.auth(req.params,function(user){
|
||||
s.checkChildProxy(req.params,function(){
|
||||
if(s.group[req.params.ke]&&s.group[req.params.ke].mon[req.params.id]){
|
||||
if(s.group[req.params.ke]&&s.group[req.params.ke].activeMonitors[req.params.id]){
|
||||
if(user.permissions.watch_stream==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.monitors.indexOf(req.params.id)===-1){
|
||||
res.end(user.lang['Not Permitted'])
|
||||
return
|
||||
|
@ -113,9 +112,9 @@ module.exports = function(s,config,lang,app){
|
|||
|
||||
var Emitter
|
||||
if(!req.params.channel){
|
||||
Emitter = s.group[req.params.ke].mon[req.params.id].emitter
|
||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitter
|
||||
}else{
|
||||
Emitter = s.group[req.params.ke].mon[req.params.id].emitterChannel[parseInt(req.params.channel)+config.pipeAddition]
|
||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[parseInt(req.params.channel)+config.pipeAddition]
|
||||
}
|
||||
res.writeHead(200, {
|
||||
'Content-Type': 'multipart/x-mixed-replace; boundary=shinobi',
|
||||
|
@ -123,33 +122,35 @@ module.exports = function(s,config,lang,app){
|
|||
'Connection': 'keep-alive',
|
||||
'Pragma': 'no-cache'
|
||||
});
|
||||
var contentWriter,content = fs.readFileSync(config.defaultMjpeg,'binary');
|
||||
res.write("--shinobi\r\n");
|
||||
res.write("Content-Type: image/jpeg\r\n");
|
||||
res.write("Content-Length: " + content.length + "\r\n");
|
||||
res.write("\r\n");
|
||||
res.write(content,'binary');
|
||||
res.write("\r\n");
|
||||
var ip = s.getClientIp(req)
|
||||
s.camera('watch_on',{
|
||||
id : req.params.id,
|
||||
ke : req.params.ke
|
||||
},{
|
||||
id : req.params.auth + ip + req.headers['user-agent']
|
||||
})
|
||||
Emitter.on('data',contentWriter=function(d){
|
||||
content = d;
|
||||
var contentWriter
|
||||
fs.readFile(config.defaultMjpeg,'binary',function(err,content){
|
||||
res.write("--shinobi\r\n");
|
||||
res.write("Content-Type: image/jpeg\r\n");
|
||||
res.write("Content-Length: " + content.length + "\r\n");
|
||||
res.write("\r\n");
|
||||
res.write(content,'binary');
|
||||
})
|
||||
res.on('close', function () {
|
||||
Emitter.removeListener('data',contentWriter)
|
||||
s.camera('watch_off',{
|
||||
res.write("\r\n");
|
||||
var ip = s.getClientIp(req)
|
||||
s.camera('watch_on',{
|
||||
id : req.params.id,
|
||||
ke : req.params.ke
|
||||
},{
|
||||
id : req.params.auth + ip + req.headers['user-agent']
|
||||
})
|
||||
});
|
||||
Emitter.on('data',contentWriter=function(d){
|
||||
content = d;
|
||||
res.write(content,'binary');
|
||||
})
|
||||
res.on('close', function () {
|
||||
Emitter.removeListener('data',contentWriter)
|
||||
s.camera('watch_off',{
|
||||
id : req.params.id,
|
||||
ke : req.params.ke
|
||||
},{
|
||||
id : req.params.auth + ip + req.headers['user-agent']
|
||||
})
|
||||
})
|
||||
})
|
||||
}else{
|
||||
res.end();
|
||||
}
|
||||
|
@ -212,20 +213,20 @@ module.exports = function(s,config,lang,app){
|
|||
s.checkChildProxy(req.params,function(){
|
||||
var Emitter,chunkChannel
|
||||
if(!req.params.channel){
|
||||
Emitter = s.group[req.params.ke].mon[req.params.id].emitter
|
||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitter
|
||||
chunkChannel = 'MAIN'
|
||||
}else{
|
||||
Emitter = s.group[req.params.ke].mon[req.params.id].emitterChannel[parseInt(req.params.channel)+config.pipeAddition]
|
||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[parseInt(req.params.channel)+config.pipeAddition]
|
||||
chunkChannel = parseInt(req.params.channel)+config.pipeAddition
|
||||
}
|
||||
if(s.group[req.params.ke].mon[req.params.id].firstStreamChunk[chunkChannel]){
|
||||
if(s.group[req.params.ke].activeMonitors[req.params.id].firstStreamChunk[chunkChannel]){
|
||||
//variable name of contentWriter
|
||||
var contentWriter
|
||||
//set headers
|
||||
res.setHeader('Content-Type', 'video/x-flv');
|
||||
res.setHeader('Access-Control-Allow-Origin','*');
|
||||
//write first frame on stream
|
||||
res.write(s.group[req.params.ke].mon[req.params.id].firstStreamChunk[chunkChannel])
|
||||
res.write(s.group[req.params.ke].activeMonitors[req.params.id].firstStreamChunk[chunkChannel])
|
||||
var ip = s.getClientIp(req)
|
||||
s.camera('watch_on',{
|
||||
id : req.params.id,
|
||||
|
@ -262,10 +263,10 @@ module.exports = function(s,config,lang,app){
|
|||
s.checkChildProxy(req.params,function(){
|
||||
var Emitter,chunkChannel
|
||||
if(!req.params.channel){
|
||||
Emitter = s.group[req.params.ke].mon[req.params.id].emitter
|
||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitter
|
||||
chunkChannel = 'MAIN'
|
||||
}else{
|
||||
Emitter = s.group[req.params.ke].mon[req.params.id].emitterChannel[parseInt(req.params.channel)+config.pipeAddition]
|
||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[parseInt(req.params.channel)+config.pipeAddition]
|
||||
chunkChannel = parseInt(req.params.channel)+config.pipeAddition
|
||||
}
|
||||
//variable name of contentWriter
|
||||
|
@ -312,9 +313,9 @@ module.exports = function(s,config,lang,app){
|
|||
if(!req.query.feed){req.query.feed='1'}
|
||||
var Emitter
|
||||
if(!req.params.feed){
|
||||
Emitter = s.group[req.params.ke].mon[req.params.id].streamIn[req.query.feed]
|
||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].streamIn[req.query.feed]
|
||||
}else{
|
||||
Emitter = s.group[req.params.ke].mon[req.params.id].emitterChannel[parseInt(req.params.feed)+config.pipeAddition]
|
||||
Emitter = s.group[req.params.ke].activeMonitors[req.params.id].emitterChannel[parseInt(req.params.feed)+config.pipeAddition]
|
||||
}
|
||||
var contentWriter
|
||||
var date = new Date();
|
||||
|
|
|
@ -634,4 +634,42 @@ module.exports = function(s,config,lang,app){
|
|||
res.end(s.prettyPrint(endData))
|
||||
},res,req)
|
||||
})
|
||||
/**
|
||||
* API : Superuser : Get Child Nodes
|
||||
*/
|
||||
app.all(config.webPaths.superApiPrefix+':auth/getChildNodes', function (req,res){
|
||||
s.superAuth(req.params,function(resp){
|
||||
var childNodesJson = {}
|
||||
Object.values(s.childNodes).forEach(function(activeNode){
|
||||
var activeCamerasCount = 0
|
||||
var activeCameras = {}
|
||||
Object.values(activeNode.activeCameras).forEach(function(monitor){
|
||||
++activeCamerasCount
|
||||
if(!activeCameras[monitor.ke])activeCameras[monitor.ke] = {}
|
||||
activeCameras[monitor.ke][monitor.mid] = {
|
||||
name: monitor.name,
|
||||
mid: monitor.mid,
|
||||
ke: monitor.ke,
|
||||
details: {
|
||||
accelerator: monitor.details.accelerator,
|
||||
auto_host: monitor.details.auto_host,
|
||||
}
|
||||
}
|
||||
})
|
||||
childNodesJson[activeNode.ip] = {
|
||||
ip: activeNode.ip,
|
||||
cpu: activeNode.cpu,
|
||||
dead: activeNode.dead,
|
||||
countCount: activeNode.countCount,
|
||||
activeMonitorsCount: activeCamerasCount,
|
||||
activeMonitors: activeCameras,
|
||||
}
|
||||
})
|
||||
var endData = {
|
||||
ok : true,
|
||||
childNodes: childNodesJson,
|
||||
}
|
||||
res.end(s.prettyPrint(endData))
|
||||
},res,req)
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue