Add "codeTester" module (Not Complete)

- Merge test functions into main app and invoke based on 1 of 2 Methods.
- Method 1 : Add `"testMode":true` to conf.json to start Shinobi in Test Mode.
- Method 2 : run `node camera.js test` in the Shinobi folder.
- CTRL+C to exit process and cleanup test files.
+ Code cleanup and bug fixes (found while testing the codeTester module)
+ Update "Entire System Export"
+ Additional Extenders
+ Make Input Map default "0" instead of "0:0"
+ Remove extra Whitespace from LICENSE and update the "Modification of this Software Product.".
merge-requests/43/head
Moe 2018-12-16 16:54:06 -08:00
parent b8f6b5283d
commit f57250e25e
16 changed files with 776 additions and 201 deletions

View File

@ -3,41 +3,41 @@ SHINOBI OPEN SOURCE SOFTWARE LICENSE AGREEMENT
Version 1, 04 June 2018
Copyright (C) 2018 [Shinobi Systems](https://shinobi.systems)
*We'll try to keep it simple. Thanks for using Shinobi Software!*
Definitions.
-----------
In this license, which also serves as a general End User License Agreement [EULA], the following
In this license, which also serves as a general End User License Agreement [EULA], the following
terms shall be interpreted by these definitions:
* "EULA" shall mean this End User Licence Agreement
* "Licensor" shall mean SHINOBI SYSTEMS
* "Licensee" shall mean YOU, or the organisation (if any) on whose behalf YOU are taking the EULA.
"SOFTWARE PRODUCTS" or "SOFTWARE" or "PRODUCTS" shall mean the Software Product this License is
included with and any additional modules or add-ons delivered by Shinobi Systems. The term
"SOFTWARE PRODUCTS" or "SOFTWARE" or "PRODUCTS" shall mean the Software Product this License is
included with and any additional modules or add-ons delivered by Shinobi Systems. The term
"SOFTWARE" includes, to the extent provided by SHINOBI SYSTEMS:
1) any revisions, updates and/or upgrades thereto;
2) any data, image or executable files, databases, data engines, computer software, or similar
2) any data, image or executable files, databases, data engines, computer software, or similar
items customarily used or distributed with computer software products;
3) anything in any form whatsoever intended to be used with or in conjunction with the SOFTWARE;
4) any associated media, documentation (including physical, electronic and on-line) and printed
4) any associated media, documentation (including physical, electronic and on-line) and printed
materials (the "Documentation").
Purpose of the Agreement.
-------------------------
**The Short**: Protect the rights of this Software Product and the LICENSOR.
**The Long**: The LICENSOR grants the LICENSEE a non-exclusive, non-transferable and perpetual
licence to use the SOFTWARE PRODUCTS listed therein and under the terms thereof. By accepting
the terms and conditions established in this agreement, the LICENSEE does not acquire any
ownership of copyright or other intellectual property rights in any part of the SOFTWARE
PRODUCTS. The LICENSEE is only entitled to use the SOFTWARE PRODUCTS in accordance with the
terms and conditions set forth by Shinobi Systems. By using the SOFTWARE PRODUCTS, the
**The Long**: The LICENSOR grants the LICENSEE a non-exclusive, non-transferable and perpetual
licence to use the SOFTWARE PRODUCTS listed therein and under the terms thereof. By accepting
the terms and conditions established in this agreement, the LICENSEE does not acquire any
ownership of copyright or other intellectual property rights in any part of the SOFTWARE
PRODUCTS. The LICENSEE is only entitled to use the SOFTWARE PRODUCTS in accordance with the
terms and conditions set forth by Shinobi Systems. By using the SOFTWARE PRODUCTS, the
LICENSEE agrees to accept the terms and conditions presented.
LICENSEE must purchase the applicable subscription in any other use case unless otherwise
granted. If the use case does not have a subscription applicable please contact a
LICENSEE must purchase the applicable subscription in any other use case unless otherwise
granted. If the use case does not have a subscription applicable please contact a
representative at support@shinobi.systems.
#### Commercial Uses
@ -50,48 +50,48 @@ representative at support@shinobi.systems.
- When used for research or educational purposes
- Testing Purposes
- Usage by Educational institutions
- Use for Emergency Services and facilties associated like Search and Rescue Services or
- Use for Emergency Services and facilties associated like Search and Rescue Services or
Ambulance Services
- Use in Health Care facility like a hospital or walk-in clinic
#### Support Services.
The Maintenance and Support Service shall be contracted and provided as per selected plan
The Maintenance and Support Service shall be contracted and provided as per selected plan
agreement, taxes will be included in all prices for Support Services.
Support Services will only provide support services as per the selected agreement.
This is not the entire agreement on support services. You must also review all agreements
This is not the entire agreement on support services. You must also review all agreements
provided with subscription plans provided.
#### Software Product Ownership.
This software is property of Shinobi Systems. LICENSEE must keep all copyright notices
This software is property of Shinobi Systems. LICENSEE must keep all copyright notices
unchanged.
#### Modification of this Software Product.
LICENSEE may modify code for personal use but must provide these changes upon request from
Shinobi Systems or an authorized Shinobi representative. LICENSEE may not alter or change
copyright notices. All code changes by LICENSEE shall fall under the copyright of Shinobi
LICENSEE may modify code for but must provide these changes upon request from
Shinobi Systems or an authorized Shinobi representative. LICENSEE may not alter or change
copyright notices. All code changes by LICENSEE shall fall under the copyright of Shinobi
Systems in the case code modified by LICENSEE is integrated into the official Shinobi code base.
#### Software Product Rebranding or "White-Labelling".
LICENSEE can remove the Shinobi branding from the front end but all copyright notices must
LICENSEE can remove the Shinobi branding from the front end but all copyright notices must
remain unchanged.
#### Software Product Contributions.
All contributed code becomes the property of Shinobi Systems. All contributors give permission
All contributed code becomes the property of Shinobi Systems. All contributors give permission
to Shinobi and Shinobi developers to use the code however it is seen fit.
#### Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM
"AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK
AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE,
YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
#### Changes to the Agreement.
Shinobi Systems reserves the right to change the license and set of terms at any time.
Continued use is agreement to those possible changes. Changes to this license will be provided
Shinobi Systems reserves the right to change the license and set of terms at any time.
Continued use is agreement to those possible changes. Changes to this license will be provided
in the commit history of the repository it is located in.
#### Legal Proceedings.
@ -100,7 +100,7 @@ All lawsuits must be filed at the Vancouver Court House.
Courthouse Vancouver Robson Square
800 Hornby St, Vancouver, BC V6Z 2C5
#### List of Included Software
#### List of Included Software
This list is completed to best of our knowledge.

View File

@ -15,14 +15,16 @@ var loadLib = function(lib){
}
//process handlers
var s = loadLib('process')(process,__dirname)
//load extender functions
loadLib('extenders')(s)
//configuration loader
var config = loadLib('config')(s)
//language loader
var lang = loadLib('language')(s,config)
//code test module
loadLib('codeTester')(s,config,lang,io)
//basic functions
loadLib('basic')(s,config)
//load extender functions
loadLib('extenders')(s,config)
//video processing engine
loadLib('ffmpeg')(s,config,function(){
//database connection : mysql, sqlite3..

View File

@ -204,8 +204,11 @@
"Backblaze Error": "Backblaze Error",
"Could not create Bucket.": "Could not create Bucket.",
"Amazon S3": "Amazon S3",
"Database": "Database",
"Database Not Found": "Database Not Found",
"User Not Found": "User Not Found",
"Save Links to Database": "Save Links to Database",
"Upload File": "Upload File",
"Bucket": "Bucket",
"Region": "Region",
"Use Global Amazon S3 Video Storage": "Use Global Amazon S3 Video Storage",

View File

@ -35,6 +35,10 @@ module.exports = function(s,config,lang){
//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){
if(!user.lang){
var details = s.parseJSON(user.details).lang
user.lang = s.getDefinitonFile(user.details.lang) || s.copySystemDefaultLanguage()
}
cb(user);
}else{
failed();
@ -43,7 +47,10 @@ module.exports = function(s,config,lang){
//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={};
cb(s.group[params.ke].users[params.auth]);
if(!s.group[params.ke].users[params.auth].lang){
s.group[params.ke].users[params.auth].lang = s.copySystemDefaultLanguage()
}
cb(s.group[params.ke].users[params.auth])
}else{
//check if key is already in memory to save query time
if(s.api[params.auth]&&s.api[params.auth].details){

View File

@ -31,12 +31,14 @@ module.exports = function(s,config){
}
}
s.parseJSON = function(string){
var parsed
try{
string = JSON.parse(string)
}catch(err){
}
return string
if(!parsed)parsed = string
return parsed
}
s.stringJSON = function(json){
try{

67
libs/codeTester.js Normal file
View File

@ -0,0 +1,67 @@
var fs = require('fs');
var execSync = require('child_process').execSync;
module.exports = function(s,config,lang,io){
var onFFmpegLoaded = function(ffmpeg){
if(process.argv[2] && process.argv[2].indexOf('test') > -1){
config.testMode = true
}
if(config.testMode === true){
config.videosDir = s.mainDirectory + '/videosTest/'
config.port = 9999
if(config.childNodes && config.childNodes.enabled === true && config.childNodes.mode === 'master'){
config.childNodes.port = 9998
}
s.ffmpegFunctions = ffmpeg
}
}
var onBeforeDatabaseLoad = function(ffmpeg){
if(config.testMode === true){
try{
execSync('rm ' + s.mainDirectory + '/shinobi-test.sqlite')
}catch(err){
}
try{
require('sqlite3')
}catch(err){
execSync('npm install sqlite3 --unsafe-perm')
}
execSync('cp ' + s.mainDirectory + '/sql/shinobi.sample.sqlite ' + s.mainDirectory + '/shinobi-test.sqlite')
config.databaseType = 'sqlite3'
config.db = {
filename: s.mainDirectory + "/shinobi-test.sqlite"
}
}
}
var onProcessReady = function(){
if(config.testMode === true){
s.location.super = s.mainDirectory + '/super-test.json'
fs.writeFileSync(s.location.super,s.s([
{
"mail":"admin@shinobi.video",
"pass":"21232f297a57a5a743894a0e4a801fc3",
"tokens":[
"111"
]
}
],null,3))
setTimeout(function(){
require(s.mainDirectory + '/test/run.js')(s,config,lang,io)
},500)
}
}
var onProcessExit = function(){
if(config.testMode === true){
execSync('rm ' + s.mainDirectory + '/shinobi-test.sqlite')
execSync('rm ' + s.location.super)
execSync('rm -rf ' + config.videosDir)
console.log('---- Temporary Files Cleaned Up')
process.exit()
}
}
//attach event handlers
s.onFFmpegLoaded(onFFmpegLoaded)
s.onBeforeDatabaseLoad(onBeforeDatabaseLoad)
s.onProcessReady(onProcessReady)
s.onProcessExit(onProcessExit)
}

View File

@ -51,6 +51,5 @@ module.exports = function(s){
if(config.childNodes.key === undefined)config.childNodes.key = [
'3123asdasdf1dtj1hjk23sdfaasd12asdasddfdbtnkkfgvesra3asdsd3123afdsfqw345'
];
return config
}

View File

@ -98,4 +98,19 @@ module.exports = function(s,config){
s.onProcessReadyExtensions.push(callback)
}
//
s.onProcessExitExtensions = []
s.onProcessExit = function(callback){
s.onProcessExitExtensions.push(callback)
}
//
s.onBeforeDatabaseLoadExtensions = []
s.onBeforeDatabaseLoad = function(callback){
s.onBeforeDatabaseLoadExtensions.push(callback)
}
//
s.onFFmpegLoadedExtensions = []
s.onFFmpegLoaded = function(callback){
s.onFFmpegLoadedExtensions.push(callback)
}
//
}

View File

@ -104,6 +104,9 @@ module.exports = function(s,config,onFinish){
ffmpeg.completeCheck = function(){
ffmpeg.checkVersion(function(){
ffmpeg.checkHwAccelMethods(function(){
s.onFFmpegLoadedExtensions.forEach(function(extender){
extender(ffmpeg)
})
onFinish(ffmpeg)
})
})
@ -132,7 +135,7 @@ module.exports = function(s,config,onFinish){
string += ' -map '+v.map
})
}else{
string += ' -map 0:0'
string += ' -map 0'
}
}
return string;

View File

@ -7,6 +7,9 @@ module.exports = function(process,__dirname){
});
// [CTRL] + [C] = exit
process.on('SIGINT', function() {
s.onProcessExitExtensions.forEach(function(extender){
extender()
})
console.log('Shinobi is Exiting...')
process.exit();
});

View File

@ -1,4 +1,7 @@
module.exports = function(s,config){
s.onBeforeDatabaseLoadExtensions.forEach(function(extender){
extender(config)
})
//sql/database connection with knex
s.databaseOptions = {
client: config.databaseType,
@ -77,21 +80,43 @@ module.exports = function(s,config){
s.databaseEngine = require('knex')(s.databaseOptions)
}
s.preQueries = function(){
//add Cloud Videos table, will remove in future
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\' COMMENT \'0:Complete,1:Read,2:Archive\',`details` text) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;',[],function(err){
// if(err)console.log(err)
var knex = s.databaseEngine
var mySQLtail = ''
if(config.databaseType === 'mysql'){
mySQLtail = ' ENGINE=InnoDB DEFAULT CHARSET=utf8'
}
//add Presets table and modernize
var createPresetsTableQuery = 'CREATE TABLE IF NOT EXISTS `Presets` ( `ke` varchar(50) DEFAULT NULL, `name` text, `details` text, `type` varchar(50) DEFAULT NULL);'
s.sqlQuery( createPresetsTableQuery + mySQLtail + ';',[],function(err){
if(err)console.error(err)
if(config.databaseType === 'sqlite3'){
var aQuery = "ALTER TABLE Presets RENAME TO _Presets_old;"
aQuery += createPresetsTableQuery
aQuery += "INSERT INTO Presets (`ke`, `name`, `details`, `type`) SELECT `ke`, `name`, `details`, `type` FROM _Presets_old;COMMIT;DROP TABLE _Presets_old;"
}else{
s.sqlQuery('ALTER TABLE `Presets` CHANGE COLUMN `type` `type` VARCHAR(50) NULL DEFAULT NULL AFTER `details`;',[],function(err){
if(err)console.error(err)
},true)
}
},true)
//add monitorStates to Preset ENUM
s.sqlQuery('ALTER TABLE `Presets` CHANGE COLUMN `type` `type` VARCHAR(50) NULL DEFAULT NULL AFTER `details`;',[],function(err){
// if(err)console.log(err)
//add Cloud Videos table, will remove in future
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)
//create Files table
s.sqlQuery('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\') ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;',[],function(err){
// if(err)console.log(err)
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){
if(err)console.error(err)
//add time column to Files table
s.sqlQuery('ALTER TABLE `Files` ADD COLUMN `time` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER `status`;',[],function(err){
// if(err)console.log(err)
},true)
if(config.databaseType === 'sqlite3'){
var aQuery = "ALTER TABLE Files RENAME TO _Files_old;"
aQuery += createPresetsTableQuery
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)console.error(err)
},true)
}
},true)
delete(s.preQueries)
}

View File

@ -4,12 +4,16 @@ 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){
module.exports = function(s,config,lang,io,processReady){
console.log('FFmpeg version : '+s.ffmpegVersion)
console.log('Node.js version : '+execSync("node -v"))
s.processReady = function(){
s.systemLog(lang.startUpText5)
process.send('ready')
s.onProcessReadyExtensions.forEach(function(extender){
extender(true)
})
if(processReady)processReady()
}
var loadedAccounts = []
var loadMonitors = function(callback){

View File

@ -21,10 +21,10 @@ module.exports = function(s,config,lang,app){
return
}
var form = s.getPostData(req)
var uid = s.getPostData(req,'uid',false)
var mail = s.getPostData(req,'mail',false)
var uid = form.uid || s.getPostData(req,'uid',false)
var mail = form.mail || s.getPostData(req,'mail',false)
if(form){
var keys = Object.keys(form)
var keys = ['details']
var condition = []
var value = []
keys.forEach(function(v){
@ -68,8 +68,9 @@ module.exports = function(s,config,lang,app){
s.closeJsonResponse(res,endData)
return
}
var uid = s.getPostData(req,'uid',false)
var mail = s.getPostData(req,'mail',false)
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])
s.sqlQuery("SELECT * FROM API WHERE ke=? AND uid=?",[req.params.ke,uid],function(err,rows){
if(rows && rows[0]){
@ -132,6 +133,12 @@ module.exports = function(s,config,lang,app){
uid: newId,
mail: form.mail
},'ADM_'+req.params.ke)
endData.user = {
details: s.parseJSON(details),
ke: req.params.ke,
uid: newId,
mail: form.mail
}
}
res.end(s.prettyPrint(endData))
})
@ -266,6 +273,7 @@ module.exports = function(s,config,lang,app){
},'GRP_' + req.params.ke)
endData.ok = true
}
endData.api = insert
s.closeJsonResponse(res,endData)
})
}else{
@ -366,7 +374,7 @@ module.exports = function(s,config,lang,app){
/**
* API : Administrator : Get Monitor State Presets List
*/
app.get([
app.all([
config.webPaths.apiPrefix+':auth/monitorStates/:ke',
config.webPaths.adminApiPrefix+':auth/monitorStates/:ke'
],function (req,res){

View File

@ -288,6 +288,7 @@ module.exports = function(s,config,lang,app){
]
)
s.tx({f:'add_account',details:form.details,ke:form.ke,uid:form.uid,mail:form.mail},'$')
endData.user = Object.assign(form,{})
//init user
s.loadGroup(form)
}
@ -324,7 +325,7 @@ module.exports = function(s,config,lang,app){
r = r[0]
var details = JSON.parse(r.details)
if(form.pass && form.pass !== ''){
if(form.pass === form.password_again){
if(form.pass === form.password_again || form.pass_again){
form.pass = s.createHash(form.pass);
}else{
endData.msg = lang["Passwords Don't Match"]
@ -335,11 +336,18 @@ module.exports = function(s,config,lang,app){
delete(form.pass);
}
delete(form.password_again);
delete(form.pass_again);
var keys = Object.keys(form)
var set = []
var values = []
keys.forEach(function(v,n){
if(set==='ke'||set==='password_again'||!form[v]){return}
if(
set === 'ke' ||
!form[v]
){
//skip
return
}
set.push(v+'=?')
if(v === 'details'){
form[v] = s.stringJSON(Object.assign(details,s.parseJSON(form[v])))
@ -360,6 +368,9 @@ module.exports = function(s,config,lang,app){
}
close()
})
}else{
endData.msg = lang['User Not Found']
close()
}
})
}else{
@ -413,35 +424,46 @@ module.exports = function(s,config,lang,app){
*/
app.all(config.webPaths.superApiPrefix+':auth/export/system', function (req,res){
s.superAuth(req.params,function(resp){
s.systemLog('Copy of the Database Exported',{
by: resp.$user.mail,
ip: resp.ip
})
var endData = {
ok : true
}
s.sqlQuery('SELECT * FROM Users',[],function(err,users){
s.sqlQuery('SELECT * FROM Monitors',[],function(err,monitors){
s.sqlQuery('SELECT * FROM API',[],function(err,api){
s.sqlQuery('SELECT * FROM Videos',[],function(err,videos){
s.sqlQuery('SELECT * FROM Logs',[],function(err,logs){
s.sqlQuery('SELECT * FROM Files',[],function(err,files){
s.sqlQuery('SELECT * FROM Presets',[],function(err,presets){
s.sqlQuery('SELECT * FROM `Cloud Videos`',[],function(err,cloudVideos){
endData.database = {
"API": api,
"Users": users,
"Monitors": monitors,
"Videos": videos,
"Presets": presets,
"Logs": logs,
"Files": files,
"Cloud Videos": cloudVideos
}
s.closeJsonResponse(res,endData)
})
})
})
})
// var database = s.getPostData(req,'database')
endData.database = {}
var tableNames = [
'Users',
'Monitors',
'API',
'Videos',
'Cloud Videos',
'Logs',
'Files',
'Presets',
]
var completedTables = 0
var tableExportLoop = function(callback){
var tableName = tableNames[completedTables]
if(tableName){
var tableIsSelected = s.getPostData(req,tableName) == 1
if(tableIsSelected){
s.sqlQuery('SELECT * FROM `' + tableName +'`',[],function(err,dataRows){
endData.database[tableName] = dataRows
++completedTables
tableExportLoop(callback)
})
})
})
}else{
++completedTables
tableExportLoop(callback)
}
}else{
callback()
}
}
tableExportLoop(function(){
s.closeJsonResponse(res,endData)
})
},res,req)
})
@ -453,9 +475,11 @@ module.exports = function(s,config,lang,app){
var endData = {
ok : false
}
console.log(req.files)
// insert data
var data = s.getPostData(req)
var database = s.getPostData(req,'database')
if(data.database)database = data.database
if(data && data.database)database = data.database
if(database){
var rowsExistingAlready = {}
var countOfRowsInserted = {}
@ -593,7 +617,6 @@ module.exports = function(s,config,lang,app){
s.closeJsonResponse(res,endData)
})
}else{
endData.database = lang['Database Not Found']
endData.msg = lang['Database Not Found']
s.closeJsonResponse(res,endData)
}

77
test.js
View File

@ -1,77 +0,0 @@
//
// Shinobi
// Copyright (C) 2016 Moe Alam, moeiscool
//
//
// # Donate
//
// If you like what I am doing here and want me to continue please consider donating :)
// PayPal : paypal@m03.ca
//
var io = new (require('socket.io'))()
//library loader
var loadLib = function(lib){
return require(__dirname+'/libs/'+lib+'.js')
}
//process handlers
var s = loadLib('process')(process,__dirname)
//configuration loader
var config = loadLib('config')(s)
//********* test.js >
config.port = 9999
if(config.childNodes && config.childNodes.enabled === true && config.childNodes.mode === 'master'){
config.childNodes.port = 9998
}
//********* test.js />
//language loader
var lang = loadLib('language')(s,config)
//basic functions
loadLib('basic')(s,config)
//load extender functions
loadLib('extenders')(s,config)
//video processing engine
loadLib('ffmpeg')(s,config,function(ffmpeg){
//********* test.js >
s.ffmpegFunctions = ffmpeg
//********* test.js />
//database connection : mysql, sqlite3..
loadLib('sql')(s,config)
//working directories : videos, streams, fileBin..
loadLib('folders')(s,config)
//authenticator functions : API, dashboard login..
loadLib('auth')(s,config,lang)
//express web server with ejs
var app = loadLib('webServer')(s,config,lang,io)
//web server routes : page handling..
loadLib('webServerPaths')(s,config,lang,app)
//web server routes for streams : streams..
loadLib('webServerStreamPaths')(s,config,lang,app)
//web server admin routes : create sub accounts, share monitors, share videos
loadLib('webServerAdminPaths')(s,config,lang,app)
//web server superuser routes : create admin accounts and manage system functions
loadLib('webServerSuperPaths')(s,config,lang,app)
//websocket connection handlers : login and streams..
loadLib('socketio')(s,config,lang,io)
//user and group functions
loadLib('user')(s,config)
//monitor/camera handlers
loadLib('monitor')(s,config,lang)
//event functions : motion, object matrix handler
loadLib('events')(s,config,lang)
//built-in detector functions : pam-diff..
loadLib('detector')(s,config)
//recording functions
loadLib('videos')(s,config,lang)
//plugins : websocket connected services..
loadLib('plugins')(s,config,lang)
//health : cpu and ram trackers..
loadLib('health')(s,config,lang,io)
//cluster module
loadLib('childNode')(s,config,lang,app,io)
//cloud uploaders : amazon s3, webdav, backblaze b2..
loadLib('cloudUploaders')(s,config,lang)
//notifiers : discord..
loadLib('notification')(s,config,lang)
//on-start actions, daemon(s) starter
require(__dirname+'/test/run.js')(s,config,lang,app,io)
})

View File

@ -1,94 +1,151 @@
module.exports = function(s,config,lang,app,io){
var fs = require('fs')
var request = require('request')
var execSync = require('child_process').execSync
module.exports = function(s,config,lang,io){
var temp = {}
var superUsers = require(s.location.super)
var requestURL = 'http://'+config.bindip + ':' + config.port +'/'
var requestSuperURL = 'http://localhost:' + config.port +'/super/' + superUsers[0].tokens[0] + '/'
var getBaseURL = function(){
return 'http://localhost:' + config.port +'/'
}
var buildRegularApiRequestURL = function(auth,path,groupKey){
return getBaseURL() + auth + '/' + path + '/' + groupKey + '/'
}
var buildAdminRequestURL = function(auth,path,groupKey){
return getBaseURL() + 'admin/' + auth + '/' + path + '/' + groupKey + '/'
}
var checkResult = function(functionName,expectedResult,testResult){
if(expectedResult !== testResult){
console.log(expectedResult,testResult)
throw new Error('x ' + functionName + ' : Failed!')
console.log('x ' + functionName + ' : Failed!')
return false
}else{
console.log('- ' + functionName + ' : Success')
console.log('✓ ' + functionName + ' : Success')
return true
}
}
var administratorAccountData = {
"mail":"test@test1.com",
"pass":"test1",
"pass_again":"test1",
"ke":"GroupKey123456",
"details":{
"factorAuth": "0",
"size": "10000",
"days": "5",
"event_days": "10",
"log_days": "10",
"max_camera": "",
"permissions": "all",
"edit_size": "1",
"edit_days": "1",
"edit_event_days": "1",
"edit_log_days": "1",
"use_admin": "1",
"use_aws_s3": "1",
"use_webdav": "1",
"use_discordbot": "1",
"use_ldap": "1"
}
}
var getAdministratorAccountData = function(){
return Object.assign(administratorAccountData,{})
}
var sampleMonitorObject = require('./testMonitor-WatchOnly.json')
var test = {
"basic.js" : {
checkRelativePath : function(){
checkRelativePath : function(next){
var expectedResult = s.mainDirectory + '/'
var testResult = s.checkRelativePath('')
checkResult('checkRelativePath',expectedResult,testResult)
checkResult('Internal Function : checkRelativePath',expectedResult,testResult)
next()
},
parseJSON : function(){
parseJSON : function(next){
var expectedResult = {}
var testResult = s.parseJSON('{}')
checkResult('parseJSON',JSON.stringify(expectedResult),JSON.stringify(testResult))
checkResult('Internal Function : parseJSON',JSON.stringify(expectedResult),JSON.stringify(testResult))
next()
},
stringJSON : function(){
stringJSON : function(next){
var expectedResult = '{}'
var testResult = s.stringJSON({})
checkResult('stringJSON',expectedResult,testResult)
checkResult('Internal Function : stringJSON',expectedResult,testResult)
next()
},
addUserPassToUrl : function(){
addUserPassToUrl : function(next){
var expectedResult = 'http://user:pass@url.com'
var testResult = s.addUserPassToUrl('http://url.com','user','pass')
checkResult('addUserPassToUrl',expectedResult,testResult)
checkResult('Internal Function : addUserPassToUrl',expectedResult,testResult)
next()
},
checkCorrectPathEnding : function(){
checkCorrectPathEnding : function(next){
var expectedResult = '/'
var testResult = s.checkCorrectPathEnding('')
checkResult('checkCorrectPathEnding',expectedResult,testResult)
checkResult('Internal Function : checkCorrectPathEnding',expectedResult,testResult)
next()
},
md5 : function(){
md5 : function(next){
var expectedResult = '5f4dcc3b5aa765d61d8327deb882cf99'
var testResult = s.md5('password')
checkResult('md5',expectedResult,testResult)
checkResult('Internal Function : md5',expectedResult,testResult)
next()
},
sha256 : function(){
sha256 : function(next){
var expectedResult = '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08'
var testResult = require('crypto').createHash('sha256').update('test').digest("hex")
checkResult('createHash/sha256',expectedResult,testResult)
checkResult('Internal Function : createHash/sha256',expectedResult,testResult)
next()
},
nameToTime : function(){
nameToTime : function(next){
var expectedResult = '2018-10-22 23:00:00'
var testResult = s.nameToTime('2018-10-22T23-00-00.mp4')
checkResult('nameToTime',expectedResult,testResult)
checkResult('Internal Function : nameToTime',expectedResult,testResult)
next()
},
ipRange : function(){
ipRange : function(next){
var expectedResult = [
'192.168.1.1',
'192.168.1.2',
'192.168.1.3'
]
var testResult = s.ipRange('192.168.1.1','192.168.1.3')
checkResult('ipRange',JSON.stringify(expectedResult),JSON.stringify(testResult))
checkResult('Internal Function : ipRange',JSON.stringify(expectedResult),JSON.stringify(testResult))
next()
},
portRange : function(){
portRange : function(next){
var expectedResult = [
8000,
8001,
8002,
]
var testResult = s.portRange(8000,8002)
checkResult('portRange',JSON.stringify(expectedResult),JSON.stringify(testResult))
checkResult('Internal Function : portRange',JSON.stringify(expectedResult),JSON.stringify(testResult))
next()
},
getFunctionParamNames : function(){
getFunctionParamNames : function(next){
var testing = function(arg1,arg2){}
var expectedResult = [
'arg1',
'arg2',
]
var testResult = s.getFunctionParamNames(testing)
checkResult('getFunctionParamNames',JSON.stringify(expectedResult),JSON.stringify(testResult))
checkResult('Internal Function : getFunctionParamNames',JSON.stringify(expectedResult),JSON.stringify(testResult))
next()
}
},
"ffmpeg.js" : {
splitForFFPMEG : function(){
splitForFFPMEG : function(next){
var expectedResult = [
'flag1',
'flag2',
'fl ag3',
]
var testResult = s.splitForFFPMEG('flag1 flag2 "fl ag3"')
checkResult('splitForFFPMEG',JSON.stringify(expectedResult),JSON.stringify(testResult))
checkResult('Internal Function : splitForFFPMEG',JSON.stringify(expectedResult),JSON.stringify(testResult))
next()
},
"ffmpeg" : function(){
"ffmpeg" : function(next){
//command string builder
var x = {tmp : ''}
s.checkDetails(sampleMonitorObject)
@ -100,7 +157,7 @@ module.exports = function(s,config,lang,app,io){
s.ffmpegFunctions.buildMainDetector(sampleMonitorObject,x)
s.ffmpegFunctions.assembleMainPieces(sampleMonitorObject,x)
var testResult = x.ffmpegCommandString
checkResult('ffmpeg',expectedResult,testResult)
checkResult('Internal Function : ffmpeg',expectedResult,testResult)
//check pipe builder
var expectedResult = []
var times = config.pipeAddition
@ -112,19 +169,453 @@ module.exports = function(s,config,lang,app,io){
}
s.ffmpegFunctions.createPipeArray(sampleMonitorObject,x)
var testResult = x.stdioPipes
checkResult('ffmpeg.createPipeArray',JSON.stringify(expectedResult),JSON.stringify(testResult))
checkResult('Internal Function : ffmpeg.createPipeArray',JSON.stringify(expectedResult),JSON.stringify(testResult))
next()
}
},
"webServer" : {
"super/accounts/saveSettings" : function(next){
console.log(requestSuperURL)
var userData = {
"mail": "admin@shinobi.video1",
"pass": "password",
"pass_again": "password"
}
var builtURL = requestSuperURL + 'accounts/saveSettings?data=' + encodeURIComponent(s.s(userData))
request(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
checkResult('API : /accounts/saveSettings',true,response.ok)
next()
})
},
"super/accounts/registerAdmin" : function(next){
var userData = getAdministratorAccountData()
var builtURL = requestSuperURL + 'accounts/registerAdmin?data=' + encodeURIComponent(s.s(userData))
request(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
administratorAccountData.uid = response.user.uid
checkResult('API : /accounts/registerAdmin',true,response.ok)
next()
})
},
"super/accounts/deleteAdmin" : function(next){
var userData = getAdministratorAccountData()
var builtURL = requestSuperURL + 'accounts/deleteAdmin?account=' + encodeURIComponent(s.s({
"mail":"test@test1.com",
"ke":"GroupKey123456",
"uid":administratorAccountData.uid
}))
request(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
checkResult('API : /accounts/deleteAdmin',true,response.ok)
next()
})
},
"super/accounts/registerAdmin (Recreate)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = requestSuperURL + 'accounts/registerAdmin?data=' + encodeURIComponent(s.s(userData))
request(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
administratorAccountData.uid = response.user.uid
checkResult('API : /accounts/registerAdmin',true,response.ok)
next()
})
},
"super/accounts/list" : function(next){
var builtURL = requestSuperURL + 'accounts/list'
request(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok === true){
// administratorAccountData = response.users[0]
}
checkResult('API : /accounts/list',1,response.users.length)
next()
})
},
"super/accounts/list/admin" : function(next){
var builtURL = requestSuperURL + 'accounts/list/admin'
request(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
checkResult('API : /accounts/list/admin',1,response.users.length)
next()
})
},
"super/accounts/list/sub" : function(next){
var builtURL = requestSuperURL + 'accounts/list/sub'
request(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
checkResult('API : /accounts/list/sub',0,response.users.length)
next()
})
},
"super/accounts/editAdmin" : function(next){
var userData = getAdministratorAccountData()
delete(userData.uid)
var builtURL = requestSuperURL + 'accounts/editAdmin?data=' + encodeURIComponent(s.s(userData)) + "&account=" + encodeURIComponent(s.s({
"mail":"test@test1.com",
"ke":"GroupKey123456"
}))
request(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(response.msg)
checkResult('API : /accounts/editAdmin',true,response.ok)
next()
})
},
"/ (Login to Admin)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = getBaseURL() + '?json=true'
request.post(builtURL,{
form : {machineID: "testMachineId", mail: "test@test1.com", pass: "test1", function: "dash"}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(response)
administratorAccountData.auth = response.$user.auth_token
checkResult('API : Login to Dashboard',true,response.ok)
next()
})
},
"Create API Key" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'api',administratorAccountData.ke) + 'add'
request.post(builtURL,{
form : {
"data": {
"ip": "0.0.0.0",
"details": {
"auth_socket": "1",
"get_monitors": "1",
"control_monitors": "1",
"get_logs": "1",
"watch_stream": "1",
"watch_snapshot": "1",
"watch_videos": "1",
"delete_videos": "1"
}
}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
temp.newApiKey = response.api.code
checkResult('API : /api/add',true,response.ok)
next()
})
},
"Delete API Key" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'api',administratorAccountData.ke) + 'delete'
request.post(builtURL,{
form : {
"data": {
"code": temp.newApiKey
}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /api/delete',true,response.ok)
next()
})
},
"/admin/accounts/register" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildAdminRequestURL(administratorAccountData.auth,'accounts',administratorAccountData.ke) + 'register'
request.post(builtURL,{
form : {
"data": {
"mail": "test@test2.com",
"pass": "test1",
"password_again": "test1"
}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
temp.subAccount = response.user
checkResult('API : /admin/accounts/register',true,response.ok)
next()
})
},
"/admin/accounts/edit" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildAdminRequestURL(administratorAccountData.auth,'accounts',administratorAccountData.ke) + 'edit'
request.post(builtURL,{
form : {
"data": {
"uid": temp.subAccount.uid,
"mail": temp.subAccount.mail,
"details": temp.subAccount.details
}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /admin/accounts/edit',true,response.ok)
next()
})
},
"/admin/accounts/delete" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildAdminRequestURL(administratorAccountData.auth,'accounts',administratorAccountData.ke) + 'delete'
request.post(builtURL,{
form : {
"data": {
"uid": temp.subAccount.uid,
"mail": temp.subAccount.mail,
}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
temp.subAccount = null
checkResult('API : /admin/accounts/delete',true,response.ok)
next()
})
},
"/configureMonitor (Add)" : function(next){
temp.monitorId = "10998"
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'configureMonitor',administratorAccountData.ke) + temp.monitorId
request.post(builtURL,{
form : {
"data": {"mode":"start","mid":temp.monitorId,"name":"ReoLinkWireless","type":"mp4","protocol":"https","host":"cdn.shinobi.video","port":"443","path":"/videos/faces.mp4","ext":"mp4","fps":"3","width":"2048","height":"1536","details":"{\"notes\":\"\",\"dir\":\"\",\"auto_host_enable\":\"1\",\"auto_host\":\"rtsp://user:pass@192.168.1.40:554/\",\"rtsp_transport\":\"tcp\",\"muser\":\"user\",\"mpass\":\"pass\",\"port_force\":null,\"fatal_max\":\"0\",\"aduration\":\"1000000\",\"probesize\":\"1000000\",\"stream_loop\":\"1\",\"sfps\":\"\",\"accelerator\":\"0\",\"hwaccel\":\"cuvid\",\"hwaccel_vcodec\":\"h264_cuvid\",\"hwaccel_device\":\"\",\"stream_type\":\"mp4\",\"stream_flv_type\":\"http\",\"stream_flv_maxLatency\":\"\",\"stream_mjpeg_clients\":\"0\",\"stream_vcodec\":\"copy\",\"stream_acodec\":\"no\",\"hls_time\":\"2\",\"hls_list_size\":\"2\",\"preset_stream\":\"\",\"signal_check\":\"\",\"signal_check_log\":\"0\",\"stream_quality\":\"1\",\"stream_fps\":\"10\",\"stream_scale_x\":\"3072\",\"stream_scale_y\":\"1728\",\"rotate_stream\":null,\"svf\":\"\",\"tv_channel\":null,\"tv_channel_id\":\"\",\"tv_channel_group_title\":\"\",\"stream_timestamp\":null,\"stream_timestamp_font\":\"\",\"stream_timestamp_font_size\":\"\",\"stream_timestamp_color\":\"\",\"stream_timestamp_box_color\":\"\",\"stream_timestamp_x\":\"\",\"stream_timestamp_y\":\"\",\"stream_watermark\":\"0\",\"stream_watermark_location\":\"\",\"stream_watermark_position\":null,\"snap\":\"0\",\"snap_fps\":\"1\",\"snap_scale_x\":\"1920\",\"snap_scale_y\":\"1072\",\"snap_vf\":\"\",\"vcodec\":\"copy\",\"crf\":\"1\",\"preset_record\":\"\",\"acodec\":\"no\",\"dqf\":\"0\",\"cutoff\":\"\",\"rotate_record\":null,\"vf\":\"\",\"timestamp\":\"0\",\"timestamp_font\":\"\",\"timestamp_font_size\":\"\",\"timestamp_color\":\"\",\"timestamp_box_color\":\"\",\"timestamp_x\":\"\",\"timestamp_y\":\"\",\"watermark\":null,\"watermark_location\":\"\",\"watermark_position\":null,\"cust_input\":\"\",\"cust_snap\":\"\",\"cust_rtmp\":\"\",\"cust_rawh264\":\"\",\"cust_detect\":\"\",\"cust_stream\":\"\",\"cust_stream_server\":\"\",\"cust_record\":\"\",\"custom_output\":\"\",\"detector\":\"0\",\"detector_pam\":\"0\",\"detector_noise_filter\":null,\"detector_webhook\":\"0\",\"detector_webhook_url\":\"\",\"detector_command_enable\":\"0\",\"detector_command\":\"\",\"detector_command_timeout\":\"\",\"detector_lock_timeout\":\"\",\"detector_save\":\"0\",\"detector_frame_save\":\"0\",\"detector_mail\":\"0\",\"detector_mail_timeout\":\"\",\"detector_record_method\":\"sip\",\"detector_trigger\":\"1\",\"detector_trigger_record_fps\":\"\",\"detector_timeout\":\"10\",\"watchdog_reset\":\"0\",\"detector_delete_motionless_videos\":\"0\",\"detector_send_frames\":\"1\",\"detector_region_of_interest\":\"0\",\"detector_fps\":\"\",\"detector_scale_x\":\"640\",\"detector_scale_y\":\"480\",\"detector_use_motion\":\"1\",\"detector_use_detect_object\":\"0\",\"detector_frame\":\"0\",\"detector_sensitivity\":\"\",\"cords\":\"[]\",\"detector_buffer_vcodec\":\"auto\",\"detector_buffer_fps\":\"\",\"detector_buffer_hls_time\":\"\",\"detector_buffer_hls_list_size\":\"\",\"detector_buffer_start_number\":\"\",\"detector_buffer_live_start_index\":\"\",\"detector_lisence_plate\":\"0\",\"detector_lisence_plate_country\":\"us\",\"detector_notrigger\":\"0\",\"detector_notrigger_mail\":\"0\",\"detector_notrigger_timeout\":\"\",\"control\":\"0\",\"control_base_url\":\"\",\"control_url_method\":null,\"control_stop\":null,\"control_url_stop_timeout\":\"\",\"control_url_center\":\"\",\"control_url_left\":\"\",\"control_url_left_stop\":\"\",\"control_url_right\":\"\",\"control_url_right_stop\":\"\",\"control_url_up\":\"\",\"control_url_up_stop\":\"\",\"control_url_down\":\"\",\"control_url_down_stop\":\"\",\"control_url_enable_nv\":\"\",\"control_url_disable_nv\":\"\",\"control_url_zoom_out\":\"\",\"control_url_zoom_out_stop\":\"\",\"control_url_zoom_in\":\"\",\"control_url_zoom_in_stop\":\"\",\"groups\":\"\",\"loglevel\":\"quiet\",\"sqllog\":\"0\",\"detector_cascades\":\"\",\"stream_channels\":\"\",\"input_maps\":\"\",\"input_map_choices\":\"\"}","shto":"[]","shfr":"[]"}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /configureMonitor (Add)',true,response.ok)
next()
})
},
"/configureMonitor (Add Second)" : function(next){
temp.monitorId2 = "10999"
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'configureMonitor',administratorAccountData.ke) + temp.monitorId2
request.post(builtURL,{
form : {
"data": {"mode":"start","mid":temp.monitorId2,"name":"ReoLinkWireless","type":"mp4","protocol":"https","host":"cdn.shinobi.video","port":"443","path":"/videos/faces.mp4","ext":"mp4","fps":"3","width":"2048","height":"1536","details":"{\"notes\":\"\",\"dir\":\"\",\"auto_host_enable\":\"1\",\"auto_host\":\"rtsp://user:pass@192.168.1.40:554/\",\"rtsp_transport\":\"tcp\",\"muser\":\"user\",\"mpass\":\"pass\",\"port_force\":null,\"fatal_max\":\"0\",\"aduration\":\"1000000\",\"probesize\":\"1000000\",\"stream_loop\":\"1\",\"sfps\":\"\",\"accelerator\":\"0\",\"hwaccel\":\"cuvid\",\"hwaccel_vcodec\":\"h264_cuvid\",\"hwaccel_device\":\"\",\"stream_type\":\"hls\",\"stream_flv_type\":\"http\",\"stream_flv_maxLatency\":\"\",\"stream_mjpeg_clients\":\"0\",\"stream_vcodec\":\"copy\",\"stream_acodec\":\"no\",\"hls_time\":\"2\",\"hls_list_size\":\"2\",\"preset_stream\":\"\",\"signal_check\":\"\",\"signal_check_log\":\"0\",\"stream_quality\":\"1\",\"stream_fps\":\"10\",\"stream_scale_x\":\"3072\",\"stream_scale_y\":\"1728\",\"rotate_stream\":null,\"svf\":\"\",\"tv_channel\":null,\"tv_channel_id\":\"\",\"tv_channel_group_title\":\"\",\"stream_timestamp\":null,\"stream_timestamp_font\":\"\",\"stream_timestamp_font_size\":\"\",\"stream_timestamp_color\":\"\",\"stream_timestamp_box_color\":\"\",\"stream_timestamp_x\":\"\",\"stream_timestamp_y\":\"\",\"stream_watermark\":\"0\",\"stream_watermark_location\":\"\",\"stream_watermark_position\":null,\"snap\":\"0\",\"snap_fps\":\"1\",\"snap_scale_x\":\"1920\",\"snap_scale_y\":\"1072\",\"snap_vf\":\"\",\"vcodec\":\"copy\",\"crf\":\"1\",\"preset_record\":\"\",\"acodec\":\"no\",\"dqf\":\"0\",\"cutoff\":\"\",\"rotate_record\":null,\"vf\":\"\",\"timestamp\":\"0\",\"timestamp_font\":\"\",\"timestamp_font_size\":\"\",\"timestamp_color\":\"\",\"timestamp_box_color\":\"\",\"timestamp_x\":\"\",\"timestamp_y\":\"\",\"watermark\":null,\"watermark_location\":\"\",\"watermark_position\":null,\"cust_input\":\"\",\"cust_snap\":\"\",\"cust_rtmp\":\"\",\"cust_rawh264\":\"\",\"cust_detect\":\"\",\"cust_stream\":\"\",\"cust_stream_server\":\"\",\"cust_record\":\"\",\"custom_output\":\"\",\"detector\":\"0\",\"detector_pam\":\"0\",\"detector_noise_filter\":null,\"detector_webhook\":\"0\",\"detector_webhook_url\":\"\",\"detector_command_enable\":\"0\",\"detector_command\":\"\",\"detector_command_timeout\":\"\",\"detector_lock_timeout\":\"\",\"detector_save\":\"0\",\"detector_frame_save\":\"0\",\"detector_mail\":\"0\",\"detector_mail_timeout\":\"\",\"detector_record_method\":\"sip\",\"detector_trigger\":\"1\",\"detector_trigger_record_fps\":\"\",\"detector_timeout\":\"10\",\"watchdog_reset\":\"0\",\"detector_delete_motionless_videos\":\"0\",\"detector_send_frames\":\"1\",\"detector_region_of_interest\":\"0\",\"detector_fps\":\"\",\"detector_scale_x\":\"640\",\"detector_scale_y\":\"480\",\"detector_use_motion\":\"1\",\"detector_use_detect_object\":\"0\",\"detector_frame\":\"0\",\"detector_sensitivity\":\"\",\"cords\":\"[]\",\"detector_buffer_vcodec\":\"auto\",\"detector_buffer_fps\":\"\",\"detector_buffer_hls_time\":\"\",\"detector_buffer_hls_list_size\":\"\",\"detector_buffer_start_number\":\"\",\"detector_buffer_live_start_index\":\"\",\"detector_lisence_plate\":\"0\",\"detector_lisence_plate_country\":\"us\",\"detector_notrigger\":\"0\",\"detector_notrigger_mail\":\"0\",\"detector_notrigger_timeout\":\"\",\"control\":\"0\",\"control_base_url\":\"\",\"control_url_method\":null,\"control_stop\":null,\"control_url_stop_timeout\":\"\",\"control_url_center\":\"\",\"control_url_left\":\"\",\"control_url_left_stop\":\"\",\"control_url_right\":\"\",\"control_url_right_stop\":\"\",\"control_url_up\":\"\",\"control_url_up_stop\":\"\",\"control_url_down\":\"\",\"control_url_down_stop\":\"\",\"control_url_enable_nv\":\"\",\"control_url_disable_nv\":\"\",\"control_url_zoom_out\":\"\",\"control_url_zoom_out_stop\":\"\",\"control_url_zoom_in\":\"\",\"control_url_zoom_in_stop\":\"\",\"groups\":\"\",\"loglevel\":\"quiet\",\"sqllog\":\"0\",\"detector_cascades\":\"\",\"stream_channels\":\"\",\"input_maps\":\"\",\"input_map_choices\":\"\"}","shto":"[]","shfr":"[]"}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /configureMonitor (Add Second)',true,response.ok)
next()
})
},
"/configureMonitor (Edit)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'configureMonitor',administratorAccountData.ke) + temp.monitorId
request.post(builtURL,{
form : {
"data": {"mode":"start","mid":temp.monitorId,"name":"ReoLinkWireless","type":"mp4","protocol":"https","host":"cdn.shinobi.video","port":"443","path":"/videos/faces.mp4","ext":"mp4","fps":"3","width":"2048","height":"1536","details":"{\"notes\":\"\",\"dir\":\"\",\"auto_host_enable\":\"1\",\"auto_host\":\"rtsp://user:pass@192.168.1.40:554/\",\"rtsp_transport\":\"tcp\",\"muser\":\"user\",\"mpass\":\"pass\",\"port_force\":null,\"fatal_max\":\"0\",\"aduration\":\"1000000\",\"probesize\":\"1000000\",\"stream_loop\":\"1\",\"sfps\":\"\",\"accelerator\":\"0\",\"hwaccel\":\"cuvid\",\"hwaccel_vcodec\":\"h264_cuvid\",\"hwaccel_device\":\"\",\"stream_type\":\"mp4\",\"stream_flv_type\":\"http\",\"stream_flv_maxLatency\":\"\",\"stream_mjpeg_clients\":\"0\",\"stream_vcodec\":\"copy\",\"stream_acodec\":\"no\",\"hls_time\":\"2\",\"hls_list_size\":\"2\",\"preset_stream\":\"\",\"signal_check\":\"\",\"signal_check_log\":\"0\",\"stream_quality\":\"1\",\"stream_fps\":\"10\",\"stream_scale_x\":\"3072\",\"stream_scale_y\":\"1728\",\"rotate_stream\":null,\"svf\":\"\",\"tv_channel\":null,\"tv_channel_id\":\"\",\"tv_channel_group_title\":\"\",\"stream_timestamp\":null,\"stream_timestamp_font\":\"\",\"stream_timestamp_font_size\":\"\",\"stream_timestamp_color\":\"\",\"stream_timestamp_box_color\":\"\",\"stream_timestamp_x\":\"\",\"stream_timestamp_y\":\"\",\"stream_watermark\":\"0\",\"stream_watermark_location\":\"\",\"stream_watermark_position\":null,\"snap\":\"0\",\"snap_fps\":\"1\",\"snap_scale_x\":\"1920\",\"snap_scale_y\":\"1072\",\"snap_vf\":\"\",\"vcodec\":\"copy\",\"crf\":\"1\",\"preset_record\":\"\",\"acodec\":\"no\",\"dqf\":\"0\",\"cutoff\":\"\",\"rotate_record\":null,\"vf\":\"\",\"timestamp\":\"0\",\"timestamp_font\":\"\",\"timestamp_font_size\":\"\",\"timestamp_color\":\"\",\"timestamp_box_color\":\"\",\"timestamp_x\":\"\",\"timestamp_y\":\"\",\"watermark\":null,\"watermark_location\":\"\",\"watermark_position\":null,\"cust_input\":\"\",\"cust_snap\":\"\",\"cust_rtmp\":\"\",\"cust_rawh264\":\"\",\"cust_detect\":\"\",\"cust_stream\":\"\",\"cust_stream_server\":\"\",\"cust_record\":\"\",\"custom_output\":\"\",\"detector\":\"0\",\"detector_pam\":\"0\",\"detector_noise_filter\":null,\"detector_webhook\":\"0\",\"detector_webhook_url\":\"\",\"detector_command_enable\":\"0\",\"detector_command\":\"\",\"detector_command_timeout\":\"\",\"detector_lock_timeout\":\"\",\"detector_save\":\"0\",\"detector_frame_save\":\"0\",\"detector_mail\":\"0\",\"detector_mail_timeout\":\"\",\"detector_record_method\":\"sip\",\"detector_trigger\":\"1\",\"detector_trigger_record_fps\":\"\",\"detector_timeout\":\"10\",\"watchdog_reset\":\"0\",\"detector_delete_motionless_videos\":\"0\",\"detector_send_frames\":\"1\",\"detector_region_of_interest\":\"0\",\"detector_fps\":\"\",\"detector_scale_x\":\"640\",\"detector_scale_y\":\"480\",\"detector_use_motion\":\"1\",\"detector_use_detect_object\":\"0\",\"detector_frame\":\"0\",\"detector_sensitivity\":\"\",\"cords\":\"[]\",\"detector_buffer_vcodec\":\"auto\",\"detector_buffer_fps\":\"\",\"detector_buffer_hls_time\":\"\",\"detector_buffer_hls_list_size\":\"\",\"detector_buffer_start_number\":\"\",\"detector_buffer_live_start_index\":\"\",\"detector_lisence_plate\":\"0\",\"detector_lisence_plate_country\":\"us\",\"detector_notrigger\":\"0\",\"detector_notrigger_mail\":\"0\",\"detector_notrigger_timeout\":\"\",\"control\":\"0\",\"control_base_url\":\"\",\"control_url_method\":null,\"control_stop\":null,\"control_url_stop_timeout\":\"\",\"control_url_center\":\"\",\"control_url_left\":\"\",\"control_url_left_stop\":\"\",\"control_url_right\":\"\",\"control_url_right_stop\":\"\",\"control_url_up\":\"\",\"control_url_up_stop\":\"\",\"control_url_down\":\"\",\"control_url_down_stop\":\"\",\"control_url_enable_nv\":\"\",\"control_url_disable_nv\":\"\",\"control_url_zoom_out\":\"\",\"control_url_zoom_out_stop\":\"\",\"control_url_zoom_in\":\"\",\"control_url_zoom_in_stop\":\"\",\"groups\":\"\",\"loglevel\":\"quiet\",\"sqllog\":\"0\",\"detector_cascades\":\"\",\"stream_channels\":\"\",\"input_maps\":\"\",\"input_map_choices\":\"\"}","shto":"[]","shfr":"[]"}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /configureMonitor (Edit)',true,response.ok)
next()
})
},
"/monitor/[MONITOR_ID] (Get)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitor',administratorAccountData.ke) + temp.monitorId
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
checkResult('API : /monitor/[MONITOR_ID] (Get)',temp.monitorId,response.mid)
next()
})
},
"/monitor (Get All)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitor',administratorAccountData.ke)
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(!checkResult('API : /monitor (Get All)',2,response.length)){
console.log(Object.keys(response))
}
next()
})
},
"/monitorStates Insert (Disable + Detector Off)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'DisableWithDetectorOff/insert'
request.post(builtURL,{
form: {
data: {
"monitors": [
{
"mode":"stop",
"mid":temp.monitorId,
"details": {
"detector": "0"
}
}
]
}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Insert (Disable + Detector Off)',true,response.ok)
next()
})
},
"/monitorStates Insert (Enable + Detector On)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'EnableWithDetectorOn/insert'
request.post(builtURL,{
form: {
data: {
"monitors": [
{
"mode":"start",
"mid":temp.monitorId,
"details": {
"detector": "1"
}
}
]
}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Insert (Enable + Detector On)',true,response.ok)
next()
})
},
"/monitorStates Insert (Continuous Recording)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'RecordOnly/insert'
request.post(builtURL,{
form: {
data: {
"monitors": [
{
"mode":"record",
"mid":temp.monitorId,
"details": {
"detector": "0"
}
}
]
}
}
},function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Insert (Continuous Recording)',true,response.ok)
next()
})
},
"/monitorStates List" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke)
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates List',true,response.ok)
next()
})
},
"/monitorStates Run Action (Disable + Detector Off)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'DisableWithDetectorOff'
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Run Action (Disable + Detector Off)',true,response.ok)
next()
})
},
"/monitorStates Run Action (Enable + Detector On)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'EnableWithDetectorOn'
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Run Action (Enable + Detector On)',true,response.ok)
next()
})
},
"/monitorStates Run Action (Continuous Recording)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'RecordOnly'
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Run Action (Continuous Recording)',true,response.ok)
next()
})
},
"/monitorStates Delete (Disable + Detector Off)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'DisableWithDetectorOff/delete'
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Delete (Disable + Detector Off)',true,response.ok)
next()
})
},
"/monitorStates Delete (Enable + Detector On)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'EnableWithDetectorOn/delete'
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Delete (Enable + Detector On)',true,response.ok)
next()
})
},
"/monitorStates Delete (Continuous Recording)" : function(next){
var userData = getAdministratorAccountData()
var builtURL = buildRegularApiRequestURL(administratorAccountData.auth,'monitorStates',administratorAccountData.ke) + 'RecordOnly/delete'
request.get(builtURL,function(err, httpResponse, body){
var response = s.parseJSON(body)
if(response.ok !== true)console.log(builtURL,response)
checkResult('API : /monitorStates Delete (Continuous Recording)',true,response.ok)
next()
})
},
}
}
console.log('----- Function Test Starting')
Object.keys(test).forEach(function(libkey){
var library = test[libkey]
console.log('--- Testing ' + libkey + '...')
Object.keys(library).forEach(function(key){
var functionTest = library[key]
functionTest()
})
console.log('-- Completed ' + libkey + '...')
var completedGroups = 0
var testGroupKeys = Object.keys(test)
var testGroupRunLoop = function(callback){
var tableName = testGroupKeys[completedGroups]
var testers = test[testGroupKeys[completedGroups]]
if(tableName){
console.log('--- Testing ' + tableName + '...')
// test functions >
var completedFunctions = 0
var testFunctionsKeys = Object.keys(testers)
var testFunctionRunLoop = function(innerCallback){
var functioName = testFunctionsKeys[completedFunctions]
var theFunction = testers[testFunctionsKeys[completedFunctions]]
if(functioName){
theFunction(function(){
++completedFunctions
testFunctionRunLoop(innerCallback)
})
}else{
innerCallback()
}
}
testFunctionRunLoop(function(){
console.log('-- Completed ' + tableName + '...')
++completedGroups
testGroupRunLoop(callback)
})
// test functions />
}else{
callback()
}
}
testGroupRunLoop(function(){
console.log('---- Function Test Ended')
})
console.log('---- Function Test Ended')
}