make all deleteOldVideos actions occur in cron.js, promisify cron funcs
parent
3a4a405e1c
commit
bf1d78235b
685
cron.js
685
cron.js
|
|
@ -41,6 +41,7 @@ const {
|
||||||
const {
|
const {
|
||||||
sqlDate,
|
sqlDate,
|
||||||
knexQuery,
|
knexQuery,
|
||||||
|
knexQueryPromise,
|
||||||
initiateDatabaseEngine
|
initiateDatabaseEngine
|
||||||
} = require('./libs/sql/utils.js')(s,config)
|
} = require('./libs/sql/utils.js')(s,config)
|
||||||
var theCronInterval = null
|
var theCronInterval = null
|
||||||
|
|
@ -108,358 +109,370 @@ const getFileBinDirectory = function(e){
|
||||||
}
|
}
|
||||||
//filters set by the user in their dashboard
|
//filters set by the user in their dashboard
|
||||||
//deleting old videos is part of the filter - config.cron.deleteOld
|
//deleting old videos is part of the filter - config.cron.deleteOld
|
||||||
const checkFilterRules = function(v,callback){
|
const checkFilterRules = function(v){
|
||||||
//filters
|
return new Promise((resolve,reject) => {
|
||||||
if(!v.d.filters||v.d.filters==''){
|
//filters
|
||||||
v.d.filters={};
|
if(!v.d.filters||v.d.filters==''){
|
||||||
}
|
v.d.filters={};
|
||||||
//delete old videos with filter
|
}
|
||||||
if(config.cron.deleteOld === true){
|
s.debugLog('Filters')
|
||||||
var where = [{
|
var keys = Object.keys(v.d.filters)
|
||||||
"p1":"end",
|
if(keys.length>0){
|
||||||
"p2":"<=",
|
keys.forEach(function(m,current){
|
||||||
"p3": sqlDate(v.d.days+" DAY")
|
// b = filter
|
||||||
}]
|
var b = v.d.filters[m];
|
||||||
//exclude monitors with their own max days
|
s.debugLog(b)
|
||||||
v.monitorsWithMaxKeepDays.forEach(function(mid){
|
if(b.enabled==="1"){
|
||||||
where.push({
|
const whereQuery = [
|
||||||
"p1":"mid",
|
['ke','=',v.ke],
|
||||||
"p2":"!=",
|
['status','!=',"0"],
|
||||||
"p3":mid,
|
['details','NOT LIKE','%"archived":"1"%'],
|
||||||
})
|
]
|
||||||
})
|
b.where.forEach(function(condition){
|
||||||
v.d.filters.deleteOldVideosByCron={
|
if(condition.p1 === 'ke'){condition.p3 = v.ke}
|
||||||
"id":"deleteOldVideosByCron",
|
whereQuery.push([condition.p1,condition.p2 || '=',condition.p3])
|
||||||
"name":"deleteOldVideosByCron",
|
|
||||||
"sort_by":"time",
|
|
||||||
"sort_by_direction":"ASC",
|
|
||||||
"limit":"",
|
|
||||||
"enabled":"1",
|
|
||||||
"archive":"0",
|
|
||||||
"email":"0",
|
|
||||||
"delete":"1",
|
|
||||||
"execute":"",
|
|
||||||
"where":where
|
|
||||||
};
|
|
||||||
}
|
|
||||||
s.debugLog('Filters')
|
|
||||||
var keys = Object.keys(v.d.filters)
|
|
||||||
if(keys.length>0){
|
|
||||||
keys.forEach(function(m,current){
|
|
||||||
// b = filter
|
|
||||||
var b = v.d.filters[m];
|
|
||||||
s.debugLog(b)
|
|
||||||
if(b.enabled==="1"){
|
|
||||||
const whereQuery = [
|
|
||||||
['ke','=',v.ke],
|
|
||||||
['status','!=',"0"],
|
|
||||||
['details','NOT LIKE','%"archived":"1"%'],
|
|
||||||
]
|
|
||||||
b.where.forEach(function(condition){
|
|
||||||
if(condition.p1 === 'ke'){condition.p3 = v.ke}
|
|
||||||
whereQuery.push([condition.p1,condition.p2 || '=',condition.p3])
|
|
||||||
})
|
|
||||||
knexQuery({
|
|
||||||
action: "select",
|
|
||||||
columns: "*",
|
|
||||||
table: "Videos",
|
|
||||||
where: whereQuery,
|
|
||||||
orderBy: [b.sort_by,b.sort_by_direction.toLowerCase()],
|
|
||||||
limit: b.limit
|
|
||||||
},(err,r) => {
|
|
||||||
if(r && r[0]){
|
|
||||||
if(r.length > 0 || config.debugLog === true){
|
|
||||||
postMessage({f:'filterMatch',msg:r.length+' SQL rows match "'+m+'"',ke:v.ke,time:moment()})
|
|
||||||
}
|
|
||||||
b.cx={
|
|
||||||
f:'filters',
|
|
||||||
name:b.name,
|
|
||||||
videos:r,
|
|
||||||
time:moment(),
|
|
||||||
ke:v.ke,
|
|
||||||
id:b.id
|
|
||||||
};
|
|
||||||
if(b.archive==="1"){
|
|
||||||
postMessage({f:'filters',ff:'archive',videos:r,time:moment(),ke:v.ke,id:b.id});
|
|
||||||
}else if(b.delete==="1"){
|
|
||||||
postMessage({f:'filters',ff:'delete',videos:r,time:moment(),ke:v.ke,id:b.id});
|
|
||||||
}
|
|
||||||
if(b.email==="1"){
|
|
||||||
b.cx.ff='email';
|
|
||||||
b.cx.delete=b.delete;
|
|
||||||
b.cx.mail=v.mail;
|
|
||||||
b.cx.execute=b.execute;
|
|
||||||
b.cx.query=b.sql;
|
|
||||||
postMessage(b.cx);
|
|
||||||
}
|
|
||||||
if(b.execute&&b.execute!==""){
|
|
||||||
postMessage({f:'filters',ff:'execute',execute:b.execute,time:moment()});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
if(current===keys.length-1){
|
|
||||||
//last filter
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
//no filters
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//database rows with no videos in the filesystem
|
|
||||||
const deleteRowsWithNoVideo = function(v,callback){
|
|
||||||
if(
|
|
||||||
config.cron.deleteNoVideo===true&&(
|
|
||||||
config.cron.deleteNoVideoRecursion===true||
|
|
||||||
(config.cron.deleteNoVideoRecursion===false&&!alreadyDeletedRowsWithNoVideosOnStart[v.ke])
|
|
||||||
)
|
|
||||||
){
|
|
||||||
alreadyDeletedRowsWithNoVideosOnStart[v.ke]=true;
|
|
||||||
knexQuery({
|
|
||||||
action: "select",
|
|
||||||
columns: "*",
|
|
||||||
table: "Videos",
|
|
||||||
where: [
|
|
||||||
['ke','=',v.ke],
|
|
||||||
['status','!=','0'],
|
|
||||||
['details','NOT LIKE','%"archived":"1"%'],
|
|
||||||
['time','<', sqlDate('10 MINUTE')],
|
|
||||||
]
|
|
||||||
},(err,evs) => {
|
|
||||||
if(evs && evs[0]){
|
|
||||||
const videosToDelete = [];
|
|
||||||
evs.forEach(function(ev){
|
|
||||||
var filename
|
|
||||||
var details
|
|
||||||
try{
|
|
||||||
details = JSON.parse(ev.details)
|
|
||||||
}catch(err){
|
|
||||||
if(details instanceof Object){
|
|
||||||
details = ev.details
|
|
||||||
}else{
|
|
||||||
details = {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var dir = getVideoDirectory(ev)
|
|
||||||
if(details.isUTC === true){
|
|
||||||
filename = localToUtc(ev.time).format('YYYY-MM-DDTHH-mm-ss')+'.'+ev.ext
|
|
||||||
}else{
|
|
||||||
filename = formattedTime(ev.time)+'.'+ev.ext
|
|
||||||
}
|
|
||||||
fileExists = fs.existsSync(dir+filename)
|
|
||||||
if(fileExists !== true){
|
|
||||||
deleteVideo(ev)
|
|
||||||
sendToWebSocket({f:'video_delete',filename:filename+'.'+ev.ext,mid:ev.mid,ke:ev.ke,time:ev.time,end: formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')},'GRP_'+ev.ke);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if(videosToDelete.length>0 || config.debugLog === true){
|
|
||||||
postMessage({f:'deleteNoVideo',msg:videosToDelete.length+' SQL rows with no file deleted',ke:v.ke,time:moment()})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setTimeout(function(){
|
|
||||||
callback()
|
|
||||||
},3000)
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//info about what the application is doing
|
|
||||||
const deleteOldLogs = function(v,callback){
|
|
||||||
if(!v.d.log_days||v.d.log_days==''){v.d.log_days=10}else{v.d.log_days=parseFloat(v.d.log_days)};
|
|
||||||
if(config.cron.deleteLogs===true&&v.d.log_days!==0){
|
|
||||||
knexQuery({
|
|
||||||
action: "delete",
|
|
||||||
table: "Logs",
|
|
||||||
where: [
|
|
||||||
['ke','=',v.ke],
|
|
||||||
['time','<', sqlDate(v.d.log_days+' DAY')],
|
|
||||||
]
|
|
||||||
},(err,rrr) => {
|
|
||||||
callback()
|
|
||||||
if(err)return console.error(err);
|
|
||||||
if(rrr.affectedRows && rrr.affectedRows.length>0 || config.debugLog === true){
|
|
||||||
postMessage({f:'deleteLogs',msg:(rrr.affectedRows || 0)+' SQL rows older than '+v.d.log_days+' days deleted',ke:v.ke,time:moment()})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//events - motion, object, etc. detections
|
|
||||||
const deleteOldEvents = function(v,callback){
|
|
||||||
if(!v.d.event_days||v.d.event_days==''){v.d.event_days=10}else{v.d.event_days=parseFloat(v.d.event_days)};
|
|
||||||
if(config.cron.deleteEvents===true&&v.d.event_days!==0){
|
|
||||||
knexQuery({
|
|
||||||
action: "delete",
|
|
||||||
table: "Events",
|
|
||||||
where: [
|
|
||||||
['ke','=',v.ke],
|
|
||||||
['time','<', sqlDate(v.d.event_days+' DAY')],
|
|
||||||
]
|
|
||||||
},(err,rrr) => {
|
|
||||||
callback()
|
|
||||||
if(err)return console.error(err);
|
|
||||||
if(rrr.affectedRows && rrr.affectedRows.length > 0 || config.debugLog === true){
|
|
||||||
postMessage({f:'deleteEvents',msg:(rrr.affectedRows || 0)+' SQL rows older than '+v.d.event_days+' days deleted',ke:v.ke,time:moment()})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//event counts
|
|
||||||
const deleteOldEventCounts = function(v,callback){
|
|
||||||
if(!v.d.event_days||v.d.event_days==''){v.d.event_days=10}else{v.d.event_days=parseFloat(v.d.event_days)};
|
|
||||||
if(config.cron.deleteEvents===true&&v.d.event_days!==0){
|
|
||||||
knexQuery({
|
|
||||||
action: "delete",
|
|
||||||
table: "Events Counts",
|
|
||||||
where: [
|
|
||||||
['ke','=',v.ke],
|
|
||||||
['time','<', sqlDate(v.d.event_days+' DAY')],
|
|
||||||
]
|
|
||||||
},(err,rrr) => {
|
|
||||||
callback()
|
|
||||||
if(err && err.code !== 'ER_NO_SUCH_TABLE')return console.error(err);
|
|
||||||
if(rrr.affectedRows && rrr.affectedRows.length > 0 || config.debugLog === true){
|
|
||||||
postMessage({f:'deleteEvents',msg:(rrr.affectedRows || 0)+' SQL rows older than '+v.d.event_days+' days deleted',ke:v.ke,time:moment()})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}else{
|
|
||||||
callback()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//check for temporary files (special archive)
|
|
||||||
const deleteOldFileBins = function(v,callback){
|
|
||||||
if(!v.d.fileBin_days||v.d.fileBin_days==''){v.d.fileBin_days=10}else{v.d.fileBin_days=parseFloat(v.d.fileBin_days)};
|
|
||||||
if(config.cron.deleteFileBins===true&&v.d.fileBin_days!==0){
|
|
||||||
var fileBinQuery = " FROM Files WHERE ke=? AND `time` < ?";
|
|
||||||
knexQuery({
|
|
||||||
action: "select",
|
|
||||||
columns: "*",
|
|
||||||
table: "Files",
|
|
||||||
where: [
|
|
||||||
['ke','=',v.ke],
|
|
||||||
['time','<', sqlDate(v.d.fileBin_days+' DAY')],
|
|
||||||
]
|
|
||||||
},(err,files) => {
|
|
||||||
if(files && files[0]){
|
|
||||||
//delete the files
|
|
||||||
files.forEach(function(file){
|
|
||||||
deleteFileBinEntry(file)
|
|
||||||
})
|
|
||||||
if(config.debugLog === true){
|
|
||||||
postMessage({
|
|
||||||
f: 'deleteFileBins',
|
|
||||||
msg: files.length + ' files older than ' + v.d.fileBin_days + ' days deleted',
|
|
||||||
ke: v.ke,
|
|
||||||
time: moment()
|
|
||||||
})
|
})
|
||||||
|
knexQuery({
|
||||||
|
action: "select",
|
||||||
|
columns: "*",
|
||||||
|
table: "Videos",
|
||||||
|
where: whereQuery,
|
||||||
|
orderBy: [b.sort_by,b.sort_by_direction.toLowerCase()],
|
||||||
|
limit: b.limit
|
||||||
|
},(err,r) => {
|
||||||
|
if(r && r[0]){
|
||||||
|
if(r.length > 0 || config.debugLog === true){
|
||||||
|
postMessage({f:'filterMatch',msg:r.length+' SQL rows match "'+m+'"',ke:v.ke,time:moment()})
|
||||||
|
}
|
||||||
|
b.cx={
|
||||||
|
f:'filters',
|
||||||
|
name:b.name,
|
||||||
|
videos:r,
|
||||||
|
time:moment(),
|
||||||
|
ke:v.ke,
|
||||||
|
id:b.id
|
||||||
|
};
|
||||||
|
if(b.archive==="1"){
|
||||||
|
postMessage({f:'filters',ff:'archive',videos:r,time:moment(),ke:v.ke,id:b.id});
|
||||||
|
}else if(b.delete==="1"){
|
||||||
|
postMessage({f:'filters',ff:'delete',videos:r,time:moment(),ke:v.ke,id:b.id});
|
||||||
|
}
|
||||||
|
if(b.email==="1"){
|
||||||
|
b.cx.ff='email';
|
||||||
|
b.cx.delete=b.delete;
|
||||||
|
b.cx.mail=v.mail;
|
||||||
|
b.cx.execute=b.execute;
|
||||||
|
b.cx.query=b.sql;
|
||||||
|
postMessage(b.cx);
|
||||||
|
}
|
||||||
|
if(b.execute&&b.execute!==""){
|
||||||
|
postMessage({f:'filters',ff:'execute',execute:b.execute,time:moment()});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
if(current===keys.length-1){
|
||||||
callback()
|
//last filter
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
//no filters
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const deleteVideosByDays = async (v,days,addedQueries) => {
|
||||||
|
const whereQuery = [
|
||||||
|
['ke','=',v.ke],
|
||||||
|
['time','<', sqlDate(days+' DAY')],
|
||||||
|
addedQueries
|
||||||
|
]
|
||||||
|
const selectResponse = await knexQueryPromise({
|
||||||
|
action: "select",
|
||||||
|
columns: "*",
|
||||||
|
table: "Videos",
|
||||||
|
where: whereQuery
|
||||||
|
})
|
||||||
|
const videoRows = selectResponse.rows
|
||||||
|
let affectedRows = 0
|
||||||
|
if(videoRows.length > 0){
|
||||||
|
var i;
|
||||||
|
for (i = 0; i < videoRows.length; i++) {
|
||||||
|
const row = videoRows[i];
|
||||||
|
const dir = getVideoDirectory(row)
|
||||||
|
const filename = formattedTime(row.time) + '.' + row.ext
|
||||||
|
await fs.promises.unlink(dir + filename)
|
||||||
|
sendToWebSocket({
|
||||||
|
f: 'video_delete',
|
||||||
|
filename: filename + '.' + row.ext,
|
||||||
|
mid: row.mid,
|
||||||
|
ke: row.ke,
|
||||||
|
time: row.time,
|
||||||
|
end: formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')
|
||||||
|
},'GRP_' + row.ke)
|
||||||
|
}
|
||||||
|
const deleteResponse = await knexQueryPromise({
|
||||||
|
action: "delete",
|
||||||
|
table: "Videos",
|
||||||
|
where: whereQuery
|
||||||
})
|
})
|
||||||
}else{
|
affectedRows = deleteResponse.rows.affectedRows
|
||||||
callback()
|
}
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
affectedRows: affectedRows,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//check for files with no database row
|
const deleteOldVideos = async (v) => {
|
||||||
const checkForOrphanedFiles = function(v,callback){
|
// v = group, admin user
|
||||||
if(config.cron.deleteOrphans === true){
|
if(config.cron.deleteOld === true){
|
||||||
console.log('"config.cron.deleteOrphans" has been removed. It has been replace by a one-time-run at startup with "config.insertOrphans". As the variable name suggests, instead of deleting, it will insert videos found without a database row.')
|
const daysOldForDeletion = !isNaN(v.d.days) ? parseFloat(v.d.days) : 5
|
||||||
console.log('By default "config.orphanedVideoCheckMax" will only check up to 20 video. You can raise this value to any number you choose but be careful as it will check that number of videos on every start.')
|
const monitorsIgnored = []
|
||||||
}
|
const monitorsResponse = await knexQueryPromise({
|
||||||
callback()
|
|
||||||
}
|
|
||||||
//user processing function
|
|
||||||
const processUser = function(number,rows){
|
|
||||||
var v = rows[number];
|
|
||||||
if(!v){
|
|
||||||
//no user object given
|
|
||||||
return
|
|
||||||
}
|
|
||||||
s.debugLog(v)
|
|
||||||
if(!alreadyDeletedRowsWithNoVideosOnStart[v.ke]){
|
|
||||||
alreadyDeletedRowsWithNoVideosOnStart[v.ke]=false;
|
|
||||||
}
|
|
||||||
if(!overlapLocks[v.ke]){
|
|
||||||
// set overlap lock
|
|
||||||
overlapLocks[v.ke] = true
|
|
||||||
//set permissions
|
|
||||||
v.d=JSON.parse(v.details);
|
|
||||||
//size
|
|
||||||
if(!v.d.size||v.d.size==''){v.d.size=10000}else{v.d.size=parseFloat(v.d.size)};
|
|
||||||
//days to keep videos
|
|
||||||
if(!v.d.days||v.d.days==''){v.d.days=5}else{v.d.days=parseFloat(v.d.days)};
|
|
||||||
knexQuery({
|
|
||||||
action: "select",
|
action: "select",
|
||||||
columns: "*",
|
columns: "*",
|
||||||
table: "Monitors",
|
table: "Monitors",
|
||||||
where: [
|
where: [
|
||||||
['ke','=',v.ke],
|
['ke','=',v.ke],
|
||||||
]
|
]
|
||||||
},(err,rr) => {
|
})
|
||||||
if(!v.d.filters||v.d.filters==''){
|
const monitorRows = monitorsResponse.rows
|
||||||
v.d.filters={};
|
var i;
|
||||||
|
for (i = 0; i < monitorRows.length; i++) {
|
||||||
|
const monitor = monitorRows[i]
|
||||||
|
const monitorId = monitor.id
|
||||||
|
const details = JSON.parse(monitor.details);
|
||||||
|
const monitorsMaxDaysToKeep = !isNaN(details.max_keep_days) ? parseFloat(details.max_keep_days) : null
|
||||||
|
if(monitorsMaxDaysToKeep){
|
||||||
|
const { affectedRows } = await deleteVideosByDays(v,monitorsMaxDaysToKeep,['mid','=',monitorId])
|
||||||
|
const hasDeletedRows = affectedRows && affectedRows.length > 0;
|
||||||
|
if(hasDeletedRows || config.debugLog === true){
|
||||||
|
postMessage({
|
||||||
|
f: 'deleteOldVideosByMonitorId',
|
||||||
|
msg: `${affectedRows} SQL rows older than ${monitorsMaxDaysToKeep} days deleted`,
|
||||||
|
ke: v.ke,
|
||||||
|
mid: monitorId,
|
||||||
|
time: moment(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
monitorsIgnored.push(['mid','!=',monitorId])
|
||||||
}
|
}
|
||||||
v.monitorsWithMaxKeepDays = []
|
}
|
||||||
rr.forEach(function(b,m){
|
const { affectedRows } = await deleteVideosByDays(v,daysOldForDeletion,monitorsIgnored)
|
||||||
b.details=JSON.parse(b.details);
|
const hasDeletedRows = affectedRows && affectedRows.length > 0;
|
||||||
if(b.details.max_keep_days&&b.details.max_keep_days!==''){
|
if(hasDeletedRows || config.debugLog === true){
|
||||||
v.monitorsWithMaxKeepDays.push(b.mid)
|
postMessage({
|
||||||
v.d.filters['deleteOldVideosByCron'+b.mid]={
|
f: 'deleteOldVideos',
|
||||||
"id":'deleteOldVideosByCron'+b.mid,
|
msg: `${affectedRows} SQL rows older than ${daysOldForDeletion} days deleted`,
|
||||||
"name":'deleteOldVideosByCron'+b.mid,
|
ke: v.ke,
|
||||||
"sort_by":"time",
|
time: moment(),
|
||||||
"sort_by_direction":"ASC",
|
})
|
||||||
"limit":"",
|
}
|
||||||
"enabled":"1",
|
}
|
||||||
"archive":"0",
|
}
|
||||||
"email":"0",
|
//database rows with no videos in the filesystem
|
||||||
"delete":"1",
|
const deleteRowsWithNoVideo = function(v){
|
||||||
"execute":"",
|
return new Promise((resolve,reject) => {
|
||||||
"where":[{
|
if(
|
||||||
"p1":"mid",
|
config.cron.deleteNoVideo===true&&(
|
||||||
"p2":"=",
|
config.cron.deleteNoVideoRecursion===true||
|
||||||
"p3":b.mid
|
(config.cron.deleteNoVideoRecursion===false&&!alreadyDeletedRowsWithNoVideosOnStart[v.ke])
|
||||||
},{
|
)
|
||||||
"p1":"end",
|
){
|
||||||
"p2":"<",
|
alreadyDeletedRowsWithNoVideosOnStart[v.ke]=true;
|
||||||
"p3": sqlDate(b.details.max_keep_days+" DAY")
|
knexQuery({
|
||||||
}]
|
action: "select",
|
||||||
};
|
columns: "*",
|
||||||
|
table: "Videos",
|
||||||
|
where: [
|
||||||
|
['ke','=',v.ke],
|
||||||
|
['status','!=','0'],
|
||||||
|
['details','NOT LIKE','%"archived":"1"%'],
|
||||||
|
['time','<', sqlDate('10 MINUTE')],
|
||||||
|
]
|
||||||
|
},(err,evs) => {
|
||||||
|
if(evs && evs[0]){
|
||||||
|
const videosToDelete = [];
|
||||||
|
evs.forEach(function(ev){
|
||||||
|
var filename
|
||||||
|
var details
|
||||||
|
try{
|
||||||
|
details = JSON.parse(ev.details)
|
||||||
|
}catch(err){
|
||||||
|
if(details instanceof Object){
|
||||||
|
details = ev.details
|
||||||
|
}else{
|
||||||
|
details = {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var dir = getVideoDirectory(ev)
|
||||||
|
filename = formattedTime(ev.time)+'.'+ev.ext
|
||||||
|
fileExists = fs.existsSync(dir+filename)
|
||||||
|
if(fileExists !== true){
|
||||||
|
deleteVideo(ev)
|
||||||
|
sendToWebSocket({f:'video_delete',filename:filename+'.'+ev.ext,mid:ev.mid,ke:ev.ke,time:ev.time,end: formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')},'GRP_'+ev.ke);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if(videosToDelete.length>0 || config.debugLog === true){
|
||||||
|
postMessage({f:'deleteNoVideo',msg:videosToDelete.length+' SQL rows with no file deleted',ke:v.ke,time:moment()})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(function(){
|
||||||
|
resolve()
|
||||||
|
},3000)
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//info about what the application is doing
|
||||||
|
const deleteOldLogs = function(v){
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
if(!v.d.log_days||v.d.log_days==''){v.d.log_days=10}else{v.d.log_days=parseFloat(v.d.log_days)};
|
||||||
|
if(config.cron.deleteLogs===true&&v.d.log_days!==0){
|
||||||
|
knexQuery({
|
||||||
|
action: "delete",
|
||||||
|
table: "Logs",
|
||||||
|
where: [
|
||||||
|
['ke','=',v.ke],
|
||||||
|
['time','<', sqlDate(v.d.log_days+' DAY')],
|
||||||
|
]
|
||||||
|
},(err,rrr) => {
|
||||||
|
resolve()
|
||||||
|
if(err)return console.error(err);
|
||||||
|
if(rrr.affectedRows && rrr.affectedRows.length>0 || config.debugLog === true){
|
||||||
|
postMessage({f:'deleteLogs',msg:(rrr.affectedRows || 0)+' SQL rows older than '+v.d.log_days+' days deleted',ke:v.ke,time:moment()})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
deleteOldLogs(v,function(){
|
}else{
|
||||||
s.debugLog('--- deleteOldLogs Complete')
|
resolve()
|
||||||
deleteOldFileBins(v,function(){
|
}
|
||||||
s.debugLog('--- deleteOldFileBins Complete')
|
})
|
||||||
deleteOldEvents(v,function(){
|
}
|
||||||
s.debugLog('--- deleteOldEvents Complete')
|
//events - motion, object, etc. detections
|
||||||
deleteOldEventCounts(v,function(){
|
const deleteOldEvents = function(v){
|
||||||
s.debugLog('--- deleteOldEventCounts Complete')
|
return new Promise((resolve,reject) => {
|
||||||
checkFilterRules(v,function(){
|
if(!v.d.event_days||v.d.event_days==''){v.d.event_days=10}else{v.d.event_days=parseFloat(v.d.event_days)};
|
||||||
s.debugLog('--- checkFilterRules Complete')
|
if(config.cron.deleteEvents===true&&v.d.event_days!==0){
|
||||||
deleteRowsWithNoVideo(v,function(){
|
knexQuery({
|
||||||
s.debugLog('--- deleteRowsWithNoVideo Complete')
|
action: "delete",
|
||||||
checkForOrphanedFiles(v,function(){
|
table: "Events",
|
||||||
//done user, unlock current, and do next
|
where: [
|
||||||
overlapLocks[v.ke]=false;
|
['ke','=',v.ke],
|
||||||
processUser(number+1,rows)
|
['time','<', sqlDate(v.d.event_days+' DAY')],
|
||||||
})
|
]
|
||||||
})
|
},(err,rrr) => {
|
||||||
})
|
resolve()
|
||||||
})
|
if(err)return console.error(err);
|
||||||
})
|
if(rrr.affectedRows && rrr.affectedRows.length > 0 || config.debugLog === true){
|
||||||
})
|
postMessage({f:'deleteEvents',msg:(rrr.affectedRows || 0)+' SQL rows older than '+v.d.event_days+' days deleted',ke:v.ke,time:moment()})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
})
|
}else{
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//event counts
|
||||||
|
const deleteOldEventCounts = function(v){
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
if(!v.d.event_days||v.d.event_days==''){v.d.event_days=10}else{v.d.event_days=parseFloat(v.d.event_days)};
|
||||||
|
if(config.cron.deleteEvents===true&&v.d.event_days!==0){
|
||||||
|
knexQuery({
|
||||||
|
action: "delete",
|
||||||
|
table: "Events Counts",
|
||||||
|
where: [
|
||||||
|
['ke','=',v.ke],
|
||||||
|
['time','<', sqlDate(v.d.event_days+' DAY')],
|
||||||
|
]
|
||||||
|
},(err,rrr) => {
|
||||||
|
resolve()
|
||||||
|
if(err && err.code !== 'ER_NO_SUCH_TABLE')return console.error(err);
|
||||||
|
if(rrr.affectedRows && rrr.affectedRows.length > 0 || config.debugLog === true){
|
||||||
|
postMessage({f:'deleteEvents',msg:(rrr.affectedRows || 0)+' SQL rows older than '+v.d.event_days+' days deleted',ke:v.ke,time:moment()})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//check for temporary files (special archive)
|
||||||
|
const deleteOldFileBins = function(v){
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
if(!v.d.fileBin_days||v.d.fileBin_days==''){v.d.fileBin_days=10}else{v.d.fileBin_days=parseFloat(v.d.fileBin_days)};
|
||||||
|
if(config.cron.deleteFileBins===true&&v.d.fileBin_days!==0){
|
||||||
|
var fileBinQuery = " FROM Files WHERE ke=? AND `time` < ?";
|
||||||
|
knexQuery({
|
||||||
|
action: "select",
|
||||||
|
columns: "*",
|
||||||
|
table: "Files",
|
||||||
|
where: [
|
||||||
|
['ke','=',v.ke],
|
||||||
|
['time','<', sqlDate(v.d.fileBin_days+' DAY')],
|
||||||
|
]
|
||||||
|
},(err,files) => {
|
||||||
|
if(files && files[0]){
|
||||||
|
//delete the files
|
||||||
|
files.forEach(function(file){
|
||||||
|
deleteFileBinEntry(file)
|
||||||
|
})
|
||||||
|
if(config.debugLog === true){
|
||||||
|
postMessage({
|
||||||
|
f: 'deleteFileBins',
|
||||||
|
msg: files.length + ' files older than ' + v.d.fileBin_days + ' days deleted',
|
||||||
|
ke: v.ke,
|
||||||
|
time: moment()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve()
|
||||||
|
})
|
||||||
|
}else{
|
||||||
|
resolve()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//user processing function
|
||||||
|
const processUser = async function(number,rows){
|
||||||
|
var v = rows[number];
|
||||||
|
if(!v){
|
||||||
|
//no user object given
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.debugLog(`Checking Group Key : ${v.ke}`)
|
||||||
|
s.debugLog(`Owner : ${v.mail}`)
|
||||||
|
if(!alreadyDeletedRowsWithNoVideosOnStart[v.ke]){
|
||||||
|
alreadyDeletedRowsWithNoVideosOnStart[v.ke]=false;
|
||||||
|
}
|
||||||
|
if(!overlapLocks[v.ke]){
|
||||||
|
overlapLocks[v.ke] = true
|
||||||
|
v.d=JSON.parse(v.details);
|
||||||
|
if(!v.d.filters||v.d.filters==''){
|
||||||
|
v.d.filters={};
|
||||||
|
}
|
||||||
|
await deleteOldVideos(v)
|
||||||
|
s.debugLog('--- deleteOldVideos Complete')
|
||||||
|
await deleteOldLogs(v)
|
||||||
|
s.debugLog('--- deleteOldLogs Complete')
|
||||||
|
await deleteOldFileBins(v)
|
||||||
|
s.debugLog('--- deleteOldFileBins Complete')
|
||||||
|
await deleteOldEvents(v)
|
||||||
|
s.debugLog('--- deleteOldEvents Complete')
|
||||||
|
await deleteOldEventCounts(v)
|
||||||
|
s.debugLog('--- deleteOldEventCounts Complete')
|
||||||
|
await checkFilterRules(v)
|
||||||
|
s.debugLog('--- checkFilterRules Complete')
|
||||||
|
await deleteRowsWithNoVideo(v)
|
||||||
|
s.debugLog('--- deleteRowsWithNoVideo Complete')
|
||||||
|
//done user, unlock current, and do next
|
||||||
|
overlapLocks[v.ke]=false;
|
||||||
|
await processUser(number+1,rows)
|
||||||
}else{
|
}else{
|
||||||
processUser(number+1,rows)
|
await processUser(number+1,rows)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//recursive function
|
//recursive function
|
||||||
|
|
|
||||||
|
|
@ -236,6 +236,17 @@ module.exports = (s,config,databaseOptions) => {
|
||||||
knexError(dbQuery,options,err)
|
knexError(dbQuery,options,err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
const knexQueryPromise = (options) => {
|
||||||
|
return new Promise((resolve,reject) => {
|
||||||
|
knexQuery(options,(err,rows) => {
|
||||||
|
resolve({
|
||||||
|
ok: !err,
|
||||||
|
err: err,
|
||||||
|
rows: rows,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
const initiateDatabaseEngine = () => {
|
const initiateDatabaseEngine = () => {
|
||||||
s.databaseEngine = knex(databaseOptions)
|
s.databaseEngine = knex(databaseOptions)
|
||||||
return s.databaseEngine
|
return s.databaseEngine
|
||||||
|
|
@ -251,6 +262,7 @@ module.exports = (s,config,databaseOptions) => {
|
||||||
processWhereCondition: processWhereCondition,
|
processWhereCondition: processWhereCondition,
|
||||||
knexError: knexError,
|
knexError: knexError,
|
||||||
knexQuery: knexQuery,
|
knexQuery: knexQuery,
|
||||||
|
knexQueryPromise: knexQueryPromise,
|
||||||
initiateDatabaseEngine: initiateDatabaseEngine
|
initiateDatabaseEngine: initiateDatabaseEngine
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ module.exports = (s,config,lang) => {
|
||||||
// const findCmd = [videosDirectory].concat(options.flags || ['-maxdepth','1'])
|
// const findCmd = [videosDirectory].concat(options.flags || ['-maxdepth','1'])
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
tempDirectory + 'orphanCheck.sh',
|
tempDirectory + 'orphanCheck.sh',
|
||||||
`find "${videosDirectory}" -maxdepth 1 -type f -exec stat -c "%y %n" {} + | sort -r | head -n ${options.checkMax}`
|
`find "${videosDirectory}" -maxdepth 1 -type f -exec stat -c "%n" {} + | sort -r | head -n ${options.checkMax}`
|
||||||
);
|
);
|
||||||
let listing = spawn('sh',[tempDirectory + 'orphanCheck.sh'])
|
let listing = spawn('sh',[tempDirectory + 'orphanCheck.sh'])
|
||||||
// const onData = options.onData ? options.onData : () => {}
|
// const onData = options.onData ? options.onData : () => {}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue