Shinobi/libs/control/onvif.js

179 lines
7.2 KiB
JavaScript

var os = require('os');
var exec = require('child_process').exec;
const onvif = require("shinobi-onvif");
const {
addCredentialsToUrl,
} = require('../common.js')
module.exports = function(s,config,lang,app,io){
const {
createSnapshot,
addCredentialsToStreamLink,
} = require('../monitor/utils.js')(s,config,lang)
const createOnvifDevice = async (onvifAuth) => {
var response = {ok: false}
const monitorConfig = s.group[onvifAuth.ke].rawMonitorConfigurations[onvifAuth.id]
const controlBaseUrl = monitorConfig.details.control_base_url || s.buildMonitorUrl(monitorConfig, true)
const controlURLOptions = s.cameraControlOptionsFromUrl(controlBaseUrl,monitorConfig)
//create onvif connection
const device = new onvif.OnvifDevice({
address : controlURLOptions.host + ':' + controlURLOptions.port,
user : controlURLOptions.username,
pass : controlURLOptions.password
})
s.group[onvifAuth.ke].activeMonitors[onvifAuth.id].onvifConnection = device
try{
const info = await device.init()
response.ok = true
response.device = device
}catch(err){
response.msg = 'Device responded with an error'
response.error = err
}
return response
}
const replaceDynamicInOptions = (Camera,options) => {
const newOptions = {}
Object.keys(options).forEach((key) => {
const value = options[key]
if(typeof value === 'string'){
newOptions[key] = value.replace(/__CURRENT_TOKEN/g,Camera.current_profile ? Camera.current_profile.token : 'NOTOKEN')
}else if(value !== undefined && value !== null){
newOptions[key] = value
}
})
return newOptions
}
const runOnvifMethod = async (onvifOptions,callback) => {
var onvifAuth = onvifOptions.auth
var response = {ok: false}
var errorMessage = function(msg,error){
response.ok = false
response.msg = msg
response.error = error
callback(response)
}
var actionCallback = function(onvifActionResponse){
response.ok = true
if(onvifActionResponse.data){
response.responseFromDevice = onvifActionResponse.data
}else{
response.responseFromDevice = onvifActionResponse
}
if(onvifActionResponse.soap)response.soap = onvifActionResponse.soap
callback(response)
}
var isEmpty = function(obj) {
for(var key in obj) {
if(obj.hasOwnProperty(key))
return false;
}
return true;
}
var doAction = function(Camera){
var completeAction = function(command){
if(command && command.then){
command.then(actionCallback).catch(function(error){
errorMessage('Device Action responded with an error',error)
})
}else if(command){
response.ok = true
response.repsonseFromDevice = command
callback(response)
}else{
response.error = 'Big Errors, Please report it to Shinobi Development'
callback(response)
}
}
var action
if(onvifAuth.service){
if(Camera.services[onvifAuth.service] === undefined){
return errorMessage('This is not an available service. Please use one of the following : '+Object.keys(Camera.services).join(', '))
}
if(Camera.services[onvifAuth.service] === null){
return errorMessage('This service is not activated. Maybe you are not connected through ONVIF. You can test by attempting to use the "Control" feature with ONVIF in Shinobi.')
}
action = Camera.services[onvifAuth.service][onvifAuth.action]
}else{
action = Camera[onvifAuth.action]
}
if(!action || typeof action !== 'function'){
errorMessage(onvifAuth.action+' is not an available ONVIF function. See https://github.com/futomi/node-onvif for functions.')
}else{
var argNames = s.getFunctionParamNames(action)
var options
var command
if(argNames[0] === 'options' || argNames[0] === 'params'){
options = replaceDynamicInOptions(Camera,onvifOptions.options || {})
response.options = options
}
if(onvifAuth.service){
command = Camera.services[onvifAuth.service][onvifAuth.action](options)
}else{
command = Camera[onvifAuth.action](options)
}
completeAction(command)
}
}
if(!s.group[onvifAuth.ke].activeMonitors[onvifAuth.id].onvifConnection){
const response = await createOnvifDevice(onvifAuth)
if(response.ok){
doAction(response.device)
}else{
errorMessage(response.msg,response.error)
}
}else{
doAction(s.group[onvifAuth.ke].activeMonitors[onvifAuth.id].onvifConnection)
}
}
async function getSnapshotFromOnvif(onvifOptions){
let theUrl;
if(onvifOptions.mid && onvifOptions.ke){
const groupKey = onvifOptions.ke
const monitorId = onvifOptions.mid
const theDevice = s.group[groupKey].activeMonitors[monitorId].onvifConnection
theUrl = addCredentialsToUrl({
username: onvifOptions.username,
password: onvifOptions.password,
url: (await theDevice.services.media.getSnapshotUri({
ProfileToken : theDevice.current_profile.token,
})).GetSnapshotUriResponse.MediaUri.Uri
});
}else{
theUrl = addCredentialsToStreamLink({
username: onvifOptions.username,
password: onvifOptions.password,
url: onvifOptions.uri
})
}
return await createSnapshot({
output: ['-s 400x400'],
url: theUrl,
})
}
/**
* 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){
s.auth(req.params,function(user){
const options = s.getPostData(req,'options',true) || s.getPostData(req,'params',true)
runOnvifMethod({
auth: {
ke: req.params.ke,
id: req.params.id,
action: req.params.action,
service: req.params.service,
},
options: options,
},(endData) => {
s.closeJsonResponse(res,endData)
})
},res,req);
})
s.getSnapshotFromOnvif = getSnapshotFromOnvif
s.createOnvifDevice = createOnvifDevice
s.runOnvifMethod = runOnvifMethod
}