update chain framework
parent
21a6d2a355
commit
a5d36f0e44
|
@ -33,6 +33,8 @@ require('./libs/ffmpeg.js')(s,config,lang, async () => {
|
|||
require('./libs/auth.js')(s,config,lang)
|
||||
//express web server with ejs
|
||||
const app = require('./libs/webServer.js')(s,config,lang,io)
|
||||
//chain framework
|
||||
require('./libs/chains.js')(s,config,lang,app,io)
|
||||
//data port
|
||||
require('./libs/dataPort.js')(s,config,lang,app,io)
|
||||
//page layout load
|
||||
|
@ -97,6 +99,4 @@ require('./libs/ffmpeg.js')(s,config,lang, async () => {
|
|||
require('./libs/cron.js')(s,config,lang)
|
||||
//video browser functions
|
||||
require('./libs/videoBrowser.js')(s,config,lang,app,io)
|
||||
//chain framework
|
||||
require('./libs/chains.js')(s,config,lang,app,io)
|
||||
})
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
module.exports = function(s,config,lang,app,io){
|
||||
s.loadedChains = {}
|
||||
s.recentSnapshots = {}
|
||||
s.loadedChainActions = {}
|
||||
const {
|
||||
loadChains,
|
||||
|
|
|
@ -1,10 +1,13 @@
|
|||
const moment = require('moment')
|
||||
module.exports = function(s,config,lang){
|
||||
const {
|
||||
findMonitorsAssociatedToTags,
|
||||
createEventBasedRecording,
|
||||
} = require('../events/utils.js')(s,config,lang)
|
||||
const {
|
||||
addExtenderAction,
|
||||
getMonitorIdFromData,
|
||||
doMonitorActionForItem,
|
||||
} = require('./utils.js')(s,config)
|
||||
// static actions
|
||||
addExtenderAction('forceRecord',(groupKey,item,data) => {
|
||||
|
@ -12,26 +15,12 @@ module.exports = function(s,config,lang){
|
|||
const monitorConfig = s.group[groupKey].rawMonitorConfigurations[monitorId]
|
||||
const monitorDetails = monitorConfig.details
|
||||
const secondBefore = (parseInt(monitorDetails.detector_buffer_seconds_before) || 5) + 1
|
||||
createEventBasedRecording(monitor,moment(eventTime).subtract(secondBefore,'seconds').format('YYYY-MM-DDTHH-mm-ss'))
|
||||
createEventBasedRecording(monitorConfig,moment(eventTime).subtract(secondBefore,'seconds').format('YYYY-MM-DDTHH-mm-ss'))
|
||||
}
|
||||
function recurseMonitorIds(monitorIds){
|
||||
for (let i = 0; i < monitorIds.length; i++) {
|
||||
const monitorId = item[i]
|
||||
beginRecording(monitorId)
|
||||
}
|
||||
}
|
||||
if(item.allMonitors){
|
||||
const monitorIds = Object.keys(s.group[groupKey].rawMonitorConfigurations)
|
||||
recurseMonitorIds(monitorIds)
|
||||
}else{
|
||||
if(item.monitorIds)recurseMonitorIds(item.monitorIds);
|
||||
// for (let i = 0; i < item.monitorTags.length; i++) {
|
||||
// const monitorIds = someHowGetMonitorIdsFromTag(item[i])
|
||||
// recurseMonitorIds(monitorIds)
|
||||
// }
|
||||
}
|
||||
})
|
||||
doMonitorActionForItem(groupKey,item,data,beginRecording)
|
||||
});
|
||||
addExtenderAction('createLog',(groupKey,item,data) => {
|
||||
const monitorId = item.monitorId || item.monitorIdFromData ? getMonitorIdFromData(data) : '$USER';
|
||||
s.userLog({
|
||||
ke: groupKey,
|
||||
mid: monitorId,
|
||||
|
@ -39,5 +28,5 @@ module.exports = function(s,config,lang){
|
|||
type: item.title,
|
||||
text: item.text
|
||||
});
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
module.exports = function(s,config){
|
||||
let loadedChains = s.loadedChains
|
||||
const {
|
||||
getMonitorIdFromData,
|
||||
} = require('./utils.js')(s,config)
|
||||
var loadedChains = s.loadedChains
|
||||
async function loadChains(){
|
||||
const selectResponse = await s.knexQueryPromise({
|
||||
action: "select",
|
||||
|
@ -10,17 +13,43 @@ module.exports = function(s,config){
|
|||
foundChains.forEach(loadChain);
|
||||
}
|
||||
function loadChain(item){
|
||||
// "item" should always be the first item in a chain
|
||||
const name = item.name
|
||||
const groupKey = item.ke
|
||||
const extenderThatStartsThis = item.ignitor
|
||||
item.conditions = JSON.parse(item.conditions)
|
||||
item.next = JSON.parse(item.next)
|
||||
if(!loadedChains[extenderThatStartsThis])loadedChains[extenderThatStartsThis] = {}
|
||||
if(!loadedChains[extenderThatStartsThis][groupKey])loadedChains[extenderThatStartsThis][groupKey] = {}
|
||||
loadedChains[extenderThatStartsThis][groupKey] = item
|
||||
loadedChains[extenderThatStartsThis][groupKey][name] = item
|
||||
}
|
||||
function unloadChain(item){
|
||||
const name = item.name
|
||||
const groupKey = item.ke
|
||||
const extenderThatStartsThis = item.ignitor
|
||||
delete(loadedChains[extenderThatStartsThis][groupKey][name])
|
||||
}
|
||||
function saveChain(item){
|
||||
|
||||
await loadChain(item)
|
||||
return s.knexQueryPromise({
|
||||
action: "insert",
|
||||
table: "Chains",
|
||||
insert: Object.assign({},item,{
|
||||
conditions: JSON.stringify(item.conditions),
|
||||
next: JSON.stringify(item.next),
|
||||
})
|
||||
})
|
||||
}
|
||||
function deleteChain(item){
|
||||
await unloadChain(item)
|
||||
return s.knexQueryPromise({
|
||||
action: "delete",
|
||||
table: "Chains",
|
||||
where: {
|
||||
ke: item.ke,
|
||||
name: item.name,
|
||||
ignitor: item.ignitor,
|
||||
}
|
||||
})
|
||||
}
|
||||
function evaluateCondition(condition,toCheck){
|
||||
var param = toCheck[condition.p1]
|
||||
|
@ -68,7 +97,7 @@ module.exports = function(s,config){
|
|||
}
|
||||
if(hasOpenBracket)++numberOfOpenAndCloseBrackets;
|
||||
if(hasCloseBracket)++numberOfOpenAndCloseBrackets;
|
||||
if(matrices)conditionChain[place].matrixCount = matrices.length
|
||||
// if(matrices)conditionChain[place].matrixCount = matrices.length
|
||||
switch(condition.p1){
|
||||
case'tag':
|
||||
case'x':
|
||||
|
@ -102,9 +131,14 @@ module.exports = function(s,config){
|
|||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
conditionChain[place].ok = evaluateCondition(condition,d.details)
|
||||
case'mid':
|
||||
var requiredMonitorId = getMonitorIdFromData(data);
|
||||
var monitorId = condition.p3;
|
||||
conditionChain[place].ok = monitorId === requiredMonitorId;
|
||||
break;
|
||||
// default:
|
||||
// conditionChain[place].ok = evaluateCondition(condition,d.details)
|
||||
// break;
|
||||
}
|
||||
}
|
||||
const allowBrackets = numberOfOpenAndCloseBrackets === 0 || isEven(numberOfOpenAndCloseBrackets);
|
||||
|
@ -143,8 +177,8 @@ module.exports = function(s,config){
|
|||
if(theChain){
|
||||
for (const groupKey in theChain) {
|
||||
const items = theChain[groupKey]
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
for (const name in items) {
|
||||
const item = items[name];
|
||||
executeChainItem(groupKey,item,data);
|
||||
}
|
||||
}
|
||||
|
@ -154,10 +188,13 @@ module.exports = function(s,config){
|
|||
return {
|
||||
loadChains,
|
||||
loadChain,
|
||||
unloadChain,
|
||||
saveChain,
|
||||
deleteChain,
|
||||
evaluateCondition,
|
||||
checkChainItemConditions,
|
||||
executeChainItem,
|
||||
addChainControllerToExtender,
|
||||
getMonitorIdFromData,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,76 @@
|
|||
module.exports = function(s,config){
|
||||
var recentSnapshots = s.recentSnapshots
|
||||
function addExtenderAction(name,theAction){
|
||||
s.loadedChainActions[name] = theAction
|
||||
}
|
||||
function getMonitorIdFromData(data){
|
||||
let monitorId = null
|
||||
data.forEach((obj) => {
|
||||
if(obj.mid || obj.id)monitorId = monitorId || obj.mid || obj.id;
|
||||
})
|
||||
return monitorId;
|
||||
}
|
||||
async function getRecentSnapshot(monitorConfig){
|
||||
const monitorId = monitorConfig.mid
|
||||
const groupKey = monitorConfig.ke
|
||||
if(recentSnapshots[`${groupKey}${monitorId}`]){
|
||||
return recentSnapshots[`${groupKey}${monitorId}`]
|
||||
}
|
||||
const { screenShot, isStaticFile } = await s.getRawSnapshotFromMonitor(monitorConfig,{
|
||||
secondsInward: monitorConfig.details.snap_seconds_inward
|
||||
});
|
||||
recentSnapshots[`${groupKey}${monitorId}`] = screenShot;
|
||||
setTimeout(() => {
|
||||
delete(recentSnapshots[`${groupKey}${monitorId}`]);
|
||||
}, 20 * 1000)
|
||||
return screenShot
|
||||
}
|
||||
async function getRecentRecording(monitorConfig){
|
||||
const monitorId = monitorConfig.mid
|
||||
const groupKey = monitorConfig.ke
|
||||
let videoPath = null
|
||||
let videoName = null
|
||||
const eventBasedRecording = await getEventBasedRecordingUponCompletion({
|
||||
ke: groupKey,
|
||||
mid: monitorId
|
||||
})
|
||||
if(eventBasedRecording.filePath){
|
||||
videoPath = eventBasedRecording.filePath
|
||||
videoName = eventBasedRecording.filename
|
||||
}else{
|
||||
const siftedVideoFileFromRam = await s.mergeDetectorBufferChunks(monitorConfig)
|
||||
videoPath = siftedVideoFileFromRam.filePath
|
||||
videoName = siftedVideoFileFromRam.filename
|
||||
}
|
||||
return {
|
||||
path: videoPath,
|
||||
name: videoName
|
||||
}
|
||||
}
|
||||
function recurseMonitorIds(monitorIds,someFunction){
|
||||
for (let i = 0; i < monitorIds.length; i++) {
|
||||
const monitorId = item[i]
|
||||
someFunction(monitorId)
|
||||
}
|
||||
}
|
||||
function doMonitorActionForItem(groupKey,item,data,someFunction){
|
||||
if(item.monitorIdFromData){
|
||||
const monitorId = getMonitorIdFromData(data)
|
||||
if(monitorId)someFunction(monitorId)
|
||||
}else if(item.allMonitors){
|
||||
const monitorIds = Object.keys(s.group[groupKey].rawMonitorConfigurations)
|
||||
recurseMonitorIds(monitorIds,someFunction)
|
||||
}else{
|
||||
if(item.monitorIds)recurseMonitorIds(item.monitorIds,someFunction);
|
||||
const monitorTags = item.monitorTags || []
|
||||
const monitorIdsFromTags = findMonitorsAssociatedToTags(groupKey,monitorTags)
|
||||
recurseMonitorIds(monitorIdsFromTags,someFunction)
|
||||
}
|
||||
}
|
||||
return {
|
||||
addExtenderAction,
|
||||
getMonitorIdFromData,
|
||||
getRecentSnapshot,
|
||||
doMonitorActionForItem,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -834,13 +834,16 @@ module.exports = (s,config,lang) => {
|
|||
return `${icon} ${tag}`;
|
||||
}
|
||||
function getObjectTagsFromMatrices(d){
|
||||
if(d.details.reason === 'motion'){
|
||||
const eventDetails = d.details
|
||||
if(!eventDetails){
|
||||
return []
|
||||
}else if(eventDetails.reason === 'motion'){
|
||||
return [getTagWithIcon(lang.Motion)]
|
||||
}else if(d.details.matrices){
|
||||
const matrices = d.details.matrices
|
||||
}else if(eventDetails.matrices){
|
||||
const matrices = eventDetails.matrices
|
||||
return [...new Set(matrices.map(matrix => getTagWithIcon(matrix.tag)))];
|
||||
}
|
||||
return [getTagWithIcon(d.details.reason)]
|
||||
return [getTagWithIcon(eventDetails.reason)]
|
||||
}
|
||||
function getObjectTagNotifyText(d){
|
||||
const monitorId = d.mid || d.id
|
||||
|
@ -870,5 +873,6 @@ module.exports = (s,config,lang) => {
|
|||
triggerEvent: triggerEvent,
|
||||
addEventDetailsToString: addEventDetailsToString,
|
||||
getEventBasedRecordingUponCompletion: getEventBasedRecordingUponCompletion,
|
||||
findMonitorsAssociatedToTags,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -302,13 +302,14 @@ module.exports = function(s,config,lang){
|
|||
}
|
||||
s.mergeDetectorBufferChunks = function(monitor,callback){
|
||||
return new Promise((resolve,reject) => {
|
||||
var pathDir = s.dir.streams+monitor.ke+'/'+monitor.id+'/'
|
||||
const monitorId = monitor.mid || monitor.id;
|
||||
var pathDir = s.dir.streams+monitor.ke+'/'+monitorId+'/'
|
||||
var mergedFile = s.formattedTime()+'.mp4'
|
||||
var mergedFilepath = pathDir+mergedFile
|
||||
fs.readdir(pathDir,function(err,streamDirItems){
|
||||
var items = []
|
||||
var copiedItems = []
|
||||
var videoLength = s.group[monitor.ke].rawMonitorConfigurations[monitor.id].details.detector_send_video_length
|
||||
var videoLength = s.group[monitor.ke].rawMonitorConfigurations[monitorId].details.detector_send_video_length
|
||||
if(!videoLength || videoLength === '')videoLength = '10'
|
||||
if(videoLength.length === 1)videoLength = '0' + videoLength
|
||||
var createMerged = function(copiedItems){
|
||||
|
|
|
@ -5,6 +5,13 @@ module.exports = function(s,config,lang,getSnapshot){
|
|||
getObjectTagNotifyText,
|
||||
getEventBasedRecordingUponCompletion,
|
||||
} = require('../events/utils.js')(s,config,lang)
|
||||
const {
|
||||
addExtenderAction,
|
||||
doMonitorActionForItem,
|
||||
} = require('./utils.js')(s,config)
|
||||
const {
|
||||
getRecentSnapshot,
|
||||
} = require('../chains/utils.js')(s,config)
|
||||
//discord bot
|
||||
if(config.discordBot === true){
|
||||
try{
|
||||
|
@ -224,6 +231,93 @@ module.exports = function(s,config,lang,getSnapshot){
|
|||
},[],monitorConfig.ke)
|
||||
}
|
||||
}
|
||||
const loadedChainAction = async (groupKey,item,data) => {
|
||||
const currentTime = new Date()
|
||||
const timeoutUntilAllowAgain = item.timeoutUntilAllowAgain
|
||||
function replaceParamsInString(monitorConfig){
|
||||
const name = monitorConfig.name
|
||||
const objectTags = data[0] && data[0].details ? data[0].details.matrices.map(item => item.tag) : []
|
||||
const newString = item.text
|
||||
.replace(/${MONITOR_NAME}/g, name)
|
||||
.replace(/${OBJECT_TAGS}/g, objectTags.join(', '))
|
||||
return newString;
|
||||
}
|
||||
const notifyText = replaceParamsInString(monitorConfig,data)
|
||||
async function sendText(){
|
||||
sendMessage({
|
||||
author: {
|
||||
name: "",
|
||||
icon_url: config.iconURL
|
||||
},
|
||||
title: notifyText,
|
||||
description: notifyText+' '+currentTime,
|
||||
fields: [],
|
||||
timestamp: currentTime,
|
||||
footer: {
|
||||
icon_url: config.iconURL,
|
||||
text: "Shinobi Systems"
|
||||
}
|
||||
},[], groupKey)
|
||||
}
|
||||
async function sendSnapshot(monitorId){
|
||||
const monitorConfig = s.group[groupKey].rawMonitorConfigurations[monitorId]
|
||||
const monitorName = monitorConfig.name
|
||||
const snapshotBuffer = await getRecentSnapshot(monitorConfig)
|
||||
// const notifyText = getObjectTagNotifyText(data[0])
|
||||
sendMessage({
|
||||
author: {
|
||||
name: monitorName,
|
||||
icon_url: config.iconURL
|
||||
},
|
||||
title: notifyText,
|
||||
description: notifyText+' '+currentTime,
|
||||
fields: [],
|
||||
timestamp: currentTime,
|
||||
footer: {
|
||||
icon_url: config.iconURL,
|
||||
text: "Shinobi Systems"
|
||||
}
|
||||
},[
|
||||
{
|
||||
attachment: snapshotBuffer,
|
||||
name: notifyText + '.jpg'
|
||||
}
|
||||
], groupKey)
|
||||
}
|
||||
async function sendVideo(monitorId){
|
||||
const monitorConfig = s.group[groupKey].rawMonitorConfigurations[monitorId]
|
||||
const monitorName = monitorConfig.name
|
||||
const video = await getRecentRecording(monitorConfig)
|
||||
// const notifyText = getObjectTagNotifyText(data[0])
|
||||
if(videoPath){
|
||||
sendMessage({
|
||||
author: {
|
||||
name: monitorName,
|
||||
icon_url: config.iconURL
|
||||
},
|
||||
title: `${notifyText}`,
|
||||
description: notifyText+' '+currentTime,
|
||||
fields: [],
|
||||
timestamp: currentTime,
|
||||
footer: {
|
||||
icon_url: config.iconURL,
|
||||
text: "Shinobi Systems"
|
||||
}
|
||||
},[
|
||||
{
|
||||
attachment: videoPath,
|
||||
name: notifyText + '.mp4'
|
||||
}
|
||||
],d.ke)
|
||||
}
|
||||
}
|
||||
async function sendMedia(monitorId){
|
||||
if(item.sendSnapshot)await sendSnapshot(monitorId);
|
||||
if(item.sendVideo)await sendVideo(monitorId);
|
||||
}
|
||||
await sendText()
|
||||
doMonitorActionForItem(groupKey,item,data,sendMedia)
|
||||
}
|
||||
s.loadGroupAppExtender(loadDiscordBotForUser)
|
||||
s.unloadGroupAppExtender(unloadDiscordBotForUser)
|
||||
s.onTwoFactorAuthCodeNotification(onTwoFactorAuthCodeNotificationForDiscord)
|
||||
|
@ -231,6 +325,7 @@ module.exports = function(s,config,lang,getSnapshot){
|
|||
s.onEventTriggerBeforeFilter(onEventTriggerBeforeFilterForDiscord)
|
||||
s.onDetectorNoTriggerTimeout(onDetectorNoTriggerTimeoutForDiscord)
|
||||
s.onMonitorUnexpectedExit(onMonitorUnexpectedExitForDiscord)
|
||||
|
||||
s.definitions["Monitor Settings"].blocks["Notifications"].info[0].info.push(
|
||||
{
|
||||
"name": "detail=notify_discord",
|
||||
|
@ -389,6 +484,9 @@ module.exports = function(s,config,lang,getSnapshot){
|
|||
}
|
||||
]
|
||||
})
|
||||
s.loadedChainActions['notifyDiscord'] = (groupKey,item,data) => {
|
||||
|
||||
}
|
||||
}catch(err){
|
||||
console.log(err)
|
||||
console.log('Could not start Discord bot, please run "npm install discord.js" inside the Shinobi folder.')
|
||||
|
|
|
@ -1,22 +1,25 @@
|
|||
// example chain
|
||||
module.exports = {
|
||||
name: 'Sample Chain',
|
||||
ke: 'groupKey',
|
||||
mid: 'monitorId',
|
||||
ignitor: 'onEventTrigger',
|
||||
conditions: [
|
||||
{p1: 'time', p2: '>', p3: '05:00:00', p4: '&&'},
|
||||
{p1: 'time', p2: '<', p3: '13:00:00', p4: '&&'}
|
||||
{p1: 'time', p2: '<', p3: '13:00:00', p4: '&&'},
|
||||
{p1: 'mid', p2: '===', p3: 'monitorId', p4: '&&'},
|
||||
],
|
||||
next: [
|
||||
{
|
||||
action: 'forceRecord',
|
||||
allMonitors: false,
|
||||
monitorIdFromData: true,
|
||||
monitorIds: [],
|
||||
monitorTags: [],
|
||||
next: [
|
||||
{
|
||||
action: 'createLog',
|
||||
monitorId: '$USER', //actual monitor id or $USER for user level log
|
||||
monitorIdFromData: true,
|
||||
// monitorId: '$USER', //actual monitor id or $USER for user level log
|
||||
title: "Text Log on Recording After Event",
|
||||
text: "Recording has Started"
|
||||
},
|
||||
|
@ -28,13 +31,14 @@ module.exports = {
|
|||
timeoutUntilAllowAgain: 1000 * 60 * 10, // 10 minutes
|
||||
sendSnapshot: true,
|
||||
sendVideo: true,
|
||||
sendForTriggeredMonitorOnly: true,
|
||||
monitorIdFromData: true,
|
||||
monitorIds: [],
|
||||
monitorTags: [],
|
||||
next: [
|
||||
{
|
||||
action: 'createLog',
|
||||
monitorId: '$USER', //actual monitor id or $USER for user level log
|
||||
monitorIdFromData: true,
|
||||
// monitorId: '$USER', //actual monitor id or $USER for user level log
|
||||
title: "Discord Note",
|
||||
text: 'Person detected in Back-1'
|
||||
},
|
||||
|
@ -45,6 +49,7 @@ module.exports = {
|
|||
sendSnapshot: true,
|
||||
sendVideo: true,
|
||||
allMonitors: false,
|
||||
monitorIdFromData: true,
|
||||
monitorIds: [],
|
||||
monitorTags: [],
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue