diff --git a/camera.js b/camera.js index 476109ad..d79bba67 100644 --- a/camera.js +++ b/camera.js @@ -16,8 +16,10 @@ s = { totalmem : os.totalmem(), //Check Platform platform : os.platform(), + //JSON stringify short-hand + s : JSON.stringify, //Pretty Print JSON - s : function(obj){return JSON.stringify(obj,null,3)}, + prettyPrint : function(obj){return JSON.stringify(obj,null,3)}, //Check if Windows isWin : (process.platform === 'win32' || process.platform === 'win64'), //UTC Offset @@ -69,6 +71,8 @@ loadLib('ffmpeg')(s,config,function(){ loadLib('health')(s,config,lang,io) //cluster module loadLib('childNode')(s,config,lang,io) + //cloud uploaders : amazon s3, webdav, blackblaze b2.. + loadLib('cloudUploaders')(s,config,lang) //on-start actions loadLib('startup')(s,config,lang) }) diff --git a/languages/en_CA.json b/languages/en_CA.json index 9bfcd6fd..a487faf6 100644 --- a/languages/en_CA.json +++ b/languages/en_CA.json @@ -190,16 +190,22 @@ "Account Info": "Account Info", "blankPassword": "Leave blank to keep same password", "2-Factor Authentication": "2-Factor Authentication", + "Use Max Storage Amount": "Use Max Storage Amount", "Max Storage Amount": "Max Storage Amount in Megabytes", "Number of Days to keep": "Number of Days to keep", "Monitor Groups": "Monitor Groups", "Group Name": "Group Name", "WebDAV": "WebDAV", + "Backblaze B2": "Backblaze B2", + "Backblaze Error": "Backblaze Error", + "Could not create Bucket.": "Could not create Bucket.", "Amazon S3": "Amazon S3", "Save Links to Database": "Save Links to Database", "Bucket": "Bucket", "Region": "Region", "Amazon S3 Upload Error": "Amazon S3 Upload Error", + "accountId": "Account ID", + "applicationKey": "Application Key", "aws_accessKeyId": "Access Key Id", "aws_secretAccessKey": "Secret Access Key", "Discord Bot": "Discord Bot", diff --git a/libs/cloudUploaders.js b/libs/cloudUploaders.js new file mode 100644 index 00000000..2a54b4ea --- /dev/null +++ b/libs/cloudUploaders.js @@ -0,0 +1,428 @@ +var fs = require('fs'); +var exec = require('child_process').exec; +var spawn = require('child_process').spawn; +var webdav = require("webdav-fs"); +module.exports = function(s,config,lang){ + // WebDAV + var beforeAccountSaveForWebDav = function(d){ + //d = save event + d.form.details.use_webdav=d.d.use_webdav + } + var cloudDiskUseStartupForWebDav = function(group,userDetails){ + group.cloudDiskUse['webdav'].name = 'WebDAV' + group.cloudDiskUse['webdav'].sizeLimitCheck = (userDetails.use_webdav_size_limit === '1') + if(!userDetails.webdav_size_limit || userDetails.webdav_size_limit === ''){ + group.cloudDiskUse['webdav'].sizeLimit = 10000 + }else{ + group.cloudDiskUse['webdav'].sizeLimit = parseFloat(userDetails.webdav_size_limit) + } + } + var loadWebDavForUser = function(e){ + // e = user + var ar = JSON.parse(e.details); + //owncloud/webdav + if(!s.group[e.ke].webdav && + ar.webdav_user&& + ar.webdav_user!==''&& + ar.webdav_pass&& + ar.webdav_pass!==''&& + ar.webdav_url&& + ar.webdav_url!=='' + ){ + if(!ar.webdav_dir||ar.webdav_dir===''){ + ar.webdav_dir='/' + } + ar.webdav_dir = s.checkCorrectPathEnding(ar.webdav_dir) + s.group[e.ke].webdav = webdav( + ar.webdav_url, + ar.webdav_user, + ar.webdav_pass + ) + } + } + var unloadWebDavForUser = function(user){ + s.group[user.ke].webdav = null + } + var deleteVideoFromWebDav = function(e,video,callback){ + // e = user + try{ + var videoDetails = JSON.parse(video.details) + }catch(err){ + var videoDetails = video.details + } + if(!videoDetails.location){ + var prefix = s.addUserPassToUrl(s.checkCorrectPathEnding(s.group[e.ke].init.webdav_url),s.group[e.ke].init.webdav_user,s.group[e.ke].init.webdav_pass) + videoDetails.location = video.href.replace(prefix,'') + } + s.group[e.ke].webdav.unlink(videoDetails.location, function(err) { + if (err) console.log(videoDetails.location,err) + callback() + }) + } + var uploadVideoToWebDav = function(e,k){ + //e = video object + //k = temporary values + if(!k)k={}; + //cloud saver - webdav + var wfs = s.group[e.ke].webdav + if(wfs && s.group[e.ke].init.use_webdav !== '0' && s.group[e.ke].init.webdav_save === "1"){ + var webdavUploadDir = s.group[e.ke].init.webdav_dir+e.ke+'/'+e.mid+'/' + var startWebDavUpload = function(){ + s.group[e.ke].mon[e.id].webdavDirExist = true + var wfsWriteStream = + fs.createReadStream(k.dir + k.filename).pipe(wfs.createWriteStream(webdavUploadDir + k.filename)) + if(s.group[e.ke].init.webdav_log === '1'){ + var webdavRemoteUrl = s.addUserPassToUrl(s.checkCorrectPathEnding(s.group[e.ke].init.webdav_url),s.group[e.ke].init.webdav_user,s.group[e.ke].init.webdav_pass) + s.group[e.ke].init.webdav_dir + e.ke + '/'+e.mid+'/'+k.filename + var save = [ + e.mid, + e.ke, + k.startTime, + 1, + s.s({ + type : 'webdav', + location : webdavUploadDir + k.filename + }), + k.filesize, + k.endTime, + webdavRemoteUrl + ] + s.sqlQuery('INSERT INTO `Cloud Videos` (mid,ke,time,status,details,size,end,href) VALUES (?,?,?,?,?,?,?,?)',save) + s.setCloudDiskUsedForGroup(e,{ + amount : k.filesizeMB, + storageType : 'webdav' + }) + s.purgeCloudDiskForGroup(e,'webdav') + } + } + if(s.group[e.ke].mon[e.id].webdavDirExist !== true){ + //check if webdav dir exist + var parentPoint = 0 + var webDavParentz = webdavUploadDir.split('/') + var webDavParents = [] + webDavParentz.forEach(function(v){ + if(v && v !== '')webDavParents.push(v) + }) + var stitchPieces = './' + var lastParentCheck = function(){ + ++parentPoint + if(parentPoint === webDavParents.length){ + startWebDavUpload() + } + checkPathPiece(webDavParents[parentPoint]) + } + var checkPathPiece = function(pathPiece){ + if(pathPiece && pathPiece !== ''){ + stitchPieces += pathPiece + '/' + wfs.stat(stitchPieces, function(error, stats) { + if(error){ + reply = { + status : error.status, + msg : lang.WebdavErrorTextTryCreatingDir, + dir : stitchPieces, + } + s.log(e,{type:lang['Webdav Error'],msg:reply}) + wfs.mkdir(stitchPieces, function(error) { + if(error){ + reply = { + status : error.status, + msg : lang.WebdavErrorTextCreatingDir, + dir : stitchPieces, + } + s.log(e,{type:lang['Webdav Error'],msg:reply}) + }else{ + lastParentCheck() + } + }) + }else{ + lastParentCheck() + } + }) + }else{ + ++parentPoint + } + } + checkPathPiece(webDavParents[0]) + }else{ + startWebDavUpload() + } + } + } + //Amazon S3 + var beforeAccountSaveForAmazonS3 = function(d){ + //d = save event + d.form.details.use_aws_s3=d.d.use_aws_s3 + } + var cloudDiskUseStartupForAmazonS3 = function(group,userDetails){ + group.cloudDiskUse['s3'].name = 'Amazon S3' + group.cloudDiskUse['s3'].sizeLimitCheck = (userDetails.use_aws_s3_size_limit === '1') + if(!userDetails.aws_s3_size_limit || userDetails.aws_s3_size_limit === ''){ + group.cloudDiskUse['s3'].sizeLimit = 10000 + }else{ + group.cloudDiskUse['s3'].sizeLimit = parseFloat(userDetails.aws_s3_size_limit) + } + } + var loadAmazonS3ForUser = function(e){ + // e = user + var ar = JSON.parse(e.details); + //Amazon S3 + if(!s.group[e.ke].aws && + !s.group[e.ke].aws_s3 && + ar.aws_s3 !== '0' && + ar.aws_accessKeyId !== ''&& + ar.aws_secretAccessKey && + ar.aws_secretAccessKey !== ''&& + ar.aws_region && + ar.aws_region !== ''&& + ar.aws_s3_bucket !== '' + ){ + if(!ar.aws_s3_dir || ar.aws_s3_dir === '/'){ + ar.aws_s3_dir = '' + } + if(ar.aws_s3_dir !== ''){ + ar.aws_s3_dir = s.checkCorrectPathEnding(ar.aws_s3_dir) + } + s.group[e.ke].aws = new require("aws-sdk") + s.group[e.ke].aws.config = new s.group[e.ke].aws.Config({ + accessKeyId: ar.aws_accessKeyId, + secretAccessKey: ar.aws_secretAccessKey, + region: ar.aws_region + }) + s.group[e.ke].aws_s3 = new s.group[e.ke].aws.S3(); + } + } + var unloadAmazonS3ForUser = function(user){ + s.group[user.ke].aws = null + s.group[user.ke].aws_s3 = null + } + var deleteVideoFromAmazonS3 = function(e,video,callback){ + // e = user + try{ + var videoDetails = JSON.parse(video.details) + }catch(err){ + var videoDetails = video.details + } + if(!videoDetails.location){ + videoDetails.location = video.href.split('.amazonaws.com')[1] + } + s.group[e.ke].aws_s3.deleteObject({ + Bucket: s.group[e.ke].init.aws_s3_bucket, + Key: videoDetails.location, + }, function(err, data) { + if (err) console.log(err); + callback() + }); + } + var uploadVideoToAmazonS3 = function(e,k){ + //e = video object + //k = temporary values + if(!k)k={}; + //cloud saver - amazon s3 + if(s.group[e.ke].aws_s3 && s.group[e.ke].init.use_aws_s3 !== '0' && s.group[e.ke].init.aws_s3_save === '1'){ + var fileStream = fs.createReadStream(k.dir+k.filename); + fileStream.on('error', function (err) { + console.error(err) + }) + var saveLocation = s.group[e.ke].init.aws_s3_dir+e.ke+'/'+e.mid+'/'+k.filename + s.group[e.ke].aws_s3.upload({ + Bucket: s.group[e.ke].init.aws_s3_bucket, + Key: saveLocation, + Body:fileStream, + ACL:'public-read' + },function(err,data){ + if(err){ + s.log(e,{type:lang['Amazon S3 Upload Error'],msg:err}) + } + if(s.group[e.ke].init.aws_s3_log === '1' && data && data.Location){ + var save = [ + e.mid, + e.ke, + k.startTime, + 1, + s.s({ + type : 's3', + location : saveLocation + }), + k.filesize, + k.endTime, + data.Location + ] + s.sqlQuery('INSERT INTO `Cloud Videos` (mid,ke,time,status,details,size,end,href) VALUES (?,?,?,?,?,?,?,?)',save) + s.setCloudDiskUsedForGroup(e,{ + amount : k.filesizeMB, + storageType : 's3' + }) + s.purgeCloudDiskForGroup(e,'s3') + } + }) + } + } + //Backblaze B2 + var beforeAccountSaveForBackblazeB2 = function(d){ + //d = save event + d.form.details.use_aws_s3=d.d.use_bb_b2 + } + var cloudDiskUseStartupForBackblazeB2 = function(group,userDetails){ + group.cloudDiskUse['b2'].name = 'Backblaze B2' + group.cloudDiskUse['b2'].sizeLimitCheck = (userDetails.use_bb_b2_size_limit === '1') + if(!userDetails.bb_b2_size_limit || userDetails.bb_b2_size_limit === ''){ + group.cloudDiskUse['b2'].sizeLimit = 10000 + }else{ + group.cloudDiskUse['b2'].sizeLimit = parseFloat(userDetails.bb_b2_size_limit) + } + } + var loadBackblazeB2ForUser = function(e){ + var ar = JSON.parse(e.details); + try{ + var B2 = require('backblaze-b2') + if(!s.group[e.ke].bb_b2 && + ar.bb_b2_accountId && + ar.bb_b2_accountId !=='' && + ar.bb_b2_applicationKey && + ar.bb_b2_applicationKey !=='' && + ar.bb_b2_bucket && + ar.bb_b2_bucket !== '' + ){ + if(!ar.bb_b2_dir || ar.bb_b2_dir === '/'){ + ar.bb_b2_dir = '' + } + if(ar.bb_b2_dir !== ''){ + ar.bb_b2_dir = s.checkCorrectPathEnding(ar.bb_b2_dir) + } + var b2 = new B2({ + accountId: ar.bb_b2_accountId, + applicationKey: ar.bb_b2_applicationKey + }) + s.group[e.ke].bb_b2 = b2 + var backblazeErr = function(err){ + // console.log(err) + s.log({mid:'$USER',ke:e.ke},{type:lang['Backblaze Error'],msg:err.data}) + } + b2.authorize().then(function(resp){ + s.group[e.ke].bb_b2_downloadUrl = resp.data.downloadUrl + b2.listBuckets().then(function(resp){ + var buckets = resp.data.buckets + var bucketN = -2 + buckets.forEach(function(item,n){ + if(item.bucketName === ar.bb_b2_bucket){ + bucketN = n + } + }) + if(bucketN > -1){ + s.group[e.ke].bb_b2_bucketId = buckets[bucketN].bucketId + }else{ + b2.createBucket( + ar.bb_b2_bucket, + 'allPublic' + ).then(function(resp){ + s.group[e.ke].bb_b2_bucketId = resp.data.bucketId + }).catch(backblazeErr) + } + }).catch(backblazeErr) + }).catch(backblazeErr) + } + }catch(err){ + console.log(err) + } + } + var unloadBackblazeB2ForUser = function(user){ + s.group[user.ke].bb_b2 = null + } + var deleteVideoFromBackblazeB2 = function(e,video,callback){ + // e = user + try{ + var videoDetails = JSON.parse(video.details) + }catch(err){ + var videoDetails = video.details + } + s.group[e.ke].bb_b2.deleteFileVersion({ + fileId: videoDetails.fileId, + fileName: videoDetails.fileName + }).then(function(resp){ + // console.log('deleteFileVersion',resp.data) + }).catch(function(err){ + console.log('deleteFileVersion',err) + }) + } + var uploadVideoToBackblazeB2 = function(e,k){ + //e = video object + //k = temporary values + if(!k)k={}; + //cloud saver - Backblaze B2 + if(s.group[e.ke].bb_b2 && s.group[e.ke].init.use_bb_b2 !== '0' && s.group[e.ke].init.bb_b2_save === '1'){ + var backblazeErr = function(err){ + // console.log(err) + s.log({mid:'$USER',ke:e.ke},{type:lang['Backblaze Error'],msg:err.data}) + } + fs.readFile(k.dir+k.filename,function(err,data){ + var backblazeSavePath = s.group[e.ke].init.bb_b2_dir+e.ke+'/'+e.mid+'/'+k.filename + var getUploadUrl = function(bucketId,callback){ + s.group[e.ke].bb_b2.getUploadUrl(bucketId).then(function(resp){ + callback(resp.data) + }).catch(backblazeErr) + } + getUploadUrl(s.group[e.ke].bb_b2_bucketId,function(req){ + s.group[e.ke].bb_b2.uploadFile({ + uploadUrl: req.uploadUrl, + uploadAuthToken: req.authorizationToken, + filename: backblazeSavePath, + data: data, + onUploadProgress: null + }).then(function(resp){ + if(s.group[e.ke].init.bb_b2_log === '1' && resp.data.fileId){ + var backblazeDownloadUrl = s.group[e.ke].bb_b2_downloadUrl + '/file/' + s.group[e.ke].init.bb_b2_bucket + '/' + backblazeSavePath + var save = [ + e.mid, + e.ke, + k.startTime, + 1, + s.s({ + type : 'b2', + bucketId : resp.data.bucketId, + fileId : resp.data.fileId, + fileName : resp.data.fileName + }), + k.filesize, + k.endTime, + backblazeDownloadUrl + ] + s.sqlQuery('INSERT INTO `Cloud Videos` (mid,ke,time,status,details,size,end,href) VALUES (?,?,?,?,?,?,?,?)',save) + s.setCloudDiskUsedForGroup(e,{ + amount : k.filesizeMB, + storageType : 'b2' + }) + s.purgeCloudDiskForGroup(e,'b2') + } + }).catch(backblazeErr) + }) + }) + } + } + //add the extenders + //webdav + s.loadGroupAppExtender(loadWebDavForUser) + s.unloadGroupAppExtender(unloadWebDavForUser) + s.insertCompletedVideoExtender(uploadVideoToWebDav) + s.deleteVideoFromCloudExtensions['webdav'] = deleteVideoFromWebDav + s.cloudDiskUseStartupExtensions['webdav'] = cloudDiskUseStartupForWebDav + s.beforeAccountSave(beforeAccountSaveForWebDav) + s.onAccountSave(cloudDiskUseStartupForWebDav) + s.cloudDisksLoader('webdav') + //amazon s3 + s.loadGroupAppExtender(loadAmazonS3ForUser) + s.unloadGroupAppExtender(unloadAmazonS3ForUser) + s.insertCompletedVideoExtender(uploadVideoToAmazonS3) + s.deleteVideoFromCloudExtensions['s3'] = deleteVideoFromAmazonS3 + s.cloudDiskUseStartupExtensions['s3'] = cloudDiskUseStartupForAmazonS3 + s.beforeAccountSave(beforeAccountSaveForAmazonS3) + s.onAccountSave(cloudDiskUseStartupForAmazonS3) + s.cloudDisksLoader('s3') + //backblaze b2 + s.loadGroupAppExtender(loadBackblazeB2ForUser) + s.unloadGroupAppExtender(unloadBackblazeB2ForUser) + s.insertCompletedVideoExtender(uploadVideoToBackblazeB2) + s.deleteVideoFromCloudExtensions['b2'] = deleteVideoFromBackblazeB2 + s.cloudDiskUseStartupExtensions['b2'] = cloudDiskUseStartupForBackblazeB2 + s.beforeAccountSave(beforeAccountSaveForBackblazeB2) + s.onAccountSave(cloudDiskUseStartupForBackblazeB2) + s.cloudDisksLoader('b2') +} diff --git a/libs/ffmpeg.js b/libs/ffmpeg.js index 8346d231..392f1315 100644 --- a/libs/ffmpeg.js +++ b/libs/ffmpeg.js @@ -84,18 +84,6 @@ module.exports = function(s,config,callback){ failback() } } - //ffmpeg location - if(!config.ffmpegDir){ - windowsFfmpegCheck(function(){ - unixFfmpegCheck(function(){ - ffbinaryCheck(function(){ - ffmpegStaticCheck(function(){ - console.log('No FFmpeg found.') - }) - }) - }) - }) - } s.splitForFFPMEG = function (ffmpegCommandAsString) { //this function ignores spaces inside quotes. return ffmpegCommandAsString.match(/\\?.|^$/g).reduce((p, c) => { @@ -846,6 +834,17 @@ module.exports = function(s,config,callback){ x.ffmpegCommandString = s.splitForFFPMEG(x.ffmpegCommandString.replace(/\s+/g,' ').trim()) return spawn(config.ffmpegDir,x.ffmpegCommandString,{detached: true,stdio:x.stdioPipes}); } + if(!config.ffmpegDir){ + windowsFfmpegCheck(function(){ + unixFfmpegCheck(function(){ + ffbinaryCheck(function(){ + ffmpegStaticCheck(function(){ + console.log('No FFmpeg found.') + }) + }) + }) + }) + } if(downloadingFfmpeg === false){ //not downloading ffmpeg completeFfmpegCheck() diff --git a/libs/health.js b/libs/health.js index fa7e65cb..d0fb721d 100644 --- a/libs/health.js +++ b/libs/health.js @@ -13,11 +13,11 @@ module.exports = function(s,config,lang,io){ s.tx({f:'diskUsed',size:s.group[e.ke].usedSpace,limit:s.group[e.ke].sizeLimit},'GRP_'+e.ke); } } - s.beat=function(){ - setTimeout(s.beat, 8000); + s.heartBeat = function(){ + setTimeout(s.heartBeat, 8000); io.sockets.emit('ping',{beat:1}); } - s.beat(); + s.heartBeat() s.cpuUsage = function(callback){ k={} switch(s.platform){ diff --git a/libs/notification.js b/libs/notification.js index 31d3a0a2..e5814173 100644 --- a/libs/notification.js +++ b/libs/notification.js @@ -32,6 +32,29 @@ module.exports = function(s,config,lang){ } }) } + var loadDiscordBotForUser = function(user){ + ar=JSON.parse(user.details); + //discordbot + if(!s.group[user.ke].discordBot && + config.discordBot === true && + ar.discordbot === '1' && + ar.discordbot_token !== '' + ){ + s.group[user.ke].discordBot = new Discord.Client() + s.group[user.ke].discordBot.on('ready', () => { + console.log(`${user.mail} : Discord Bot Logged in as ${s.group[user.ke].discordBot.user.tag}!`) + }) + s.group[user.ke].discordBot.login(ar.discordbot_token) + } + } + var unloadDiscordBotForUser = function(user){ + if(s.group[user.ke].discordBot && s.group[user.ke].discordBot.destroy){ + s.group[user.ke].discordBot.destroy() + delete(s.group[user.ke].discordBot) + } + } + s.loadGroupAppExtender(loadDiscordBotForUser) + s.unloadGroupAppExtender(unloadDiscordBotForUser) }catch(err){ console.log('Could not start Discord bot, please run "npm install discord.js" inside the Shinobi folder.') s.discordMsg = function(){} diff --git a/libs/socketio.js b/libs/socketio.js index bffa65c3..8f12ab46 100644 --- a/libs/socketio.js +++ b/libs/socketio.js @@ -597,13 +597,14 @@ module.exports = function(s,config,lang,io){ } ///unchangeable from client side, so reset them in case they did. d.form.details=JSON.parse(d.form.details) + s.beforeAccountSaveExtensions.forEach(function(extender){ + extender(d) + }) //admin permissions d.form.details.permissions=d.d.permissions d.form.details.edit_size=d.d.edit_size d.form.details.edit_days=d.d.edit_days d.form.details.use_admin=d.d.use_admin - d.form.details.use_webdav=d.d.use_webdav - d.form.details.use_aws_s3=d.d.use_aws_s3 d.form.details.use_ldap=d.d.use_ldap //check if(d.d.edit_days=="0"){ @@ -624,7 +625,7 @@ module.exports = function(s,config,lang,io){ if(d.d.days){d.form.details.days=d.d.days;} delete(d.form.details.mon_groups) } - var newSize = d.form.details.size + var newSize = d.form.details.size || 10000 d.form.details=JSON.stringify(d.form.details) /// d.set=[],d.ar=[]; @@ -637,14 +638,15 @@ module.exports = function(s,config,lang,io){ d.ar.push(d.ke),d.ar.push(d.uid); s.sqlQuery('UPDATE Users SET '+d.set.join(',')+' WHERE ke=? AND uid=?',d.ar,function(err,r){ if(!d.d.sub){ + var user = Object.assign(d.form,{ke : d.ke}) + var userDetails = JSON.parse(d.form.details) s.group[d.ke].sizeLimit = parseFloat(newSize) - s.group[d.ke].webdav = null - s.group[d.ke].aws = null - s.group[d.ke].aws_s3 = null - if(s.group[d.ke].discordBot && s.group[d.ke].discordBot.destroy){ - s.group[d.ke].discordBot.destroy() - delete(s.group[d.ke].discordBot) - } + s.onAccountSaveExtensions.forEach(function(extender){ + extender(s.group[d.ke],userDetails) + }) + s.unloadGroupAppExtensions.forEach(function(extender){ + extender(user) + }) s.loadGroupApps(d) } tx({f:'user_settings_change',uid:d.uid,ke:d.ke,form:d.form}); diff --git a/libs/startup.js b/libs/startup.js index 8b9190b5..3281eea8 100644 --- a/libs/startup.js +++ b/libs/startup.js @@ -27,31 +27,85 @@ module.exports = function(s,config,lang,io){ callback() }) } + var loadDiskUseForUser = function(user,callback){ + s.systemLog(user.mail+' : '+lang.startUpText0) + var userDetails = JSON.parse(user.details) + user.size = 0 + user.limit = userDetails.size + s.sqlQuery('SELECT * FROM Videos WHERE ke=? AND status!=?',[user.ke,0],function(err,videos){ + if(videos && videos[0]){ + videos.forEach(function(video){ + user.size += video.size + }) + } + s.systemLog(user.mail+' : '+lang.startUpText1+' : '+videos.length,user.size) + callback() + }) + } + var loadCloudDiskUseForUser = function(user,callback){ + var userDetails = JSON.parse(user.details) + user.cloudDiskUse = {} + user.size = 0 + user.limit = userDetails.size + s.cloudDisksLoaded.forEach(function(storageType){ + user.cloudDiskUse[storageType] = { + usedSpace : 0, + firstCount : 0 + } + if(s.cloudDiskUseStartupExtensions[storageType])s.cloudDiskUseStartupExtensions[storageType](user,userDetails) + }) + s.sqlQuery('SELECT * FROM `Cloud Videos` WHERE ke=? AND status!=?',[user.ke,0],function(err,videos){ + if(videos && videos[0]){ + videos.forEach(function(video){ + var storageType = JSON.parse(video.details).type + if(!storageType)storageType = 's3' + user.cloudDiskUse[storageType].usedSpace += (video.size /1000000) + ++user.cloudDiskUse[storageType].firstCount + }) + s.cloudDisksLoaded.forEach(function(storageType){ + var firstCount = user.cloudDiskUse[storageType].firstCount + s.systemLog(user.mail+' : '+lang.startUpText1+' : '+firstCount,storageType,user.cloudDiskUse[storageType].usedSpace) + delete(user.cloudDiskUse[storageType].firstCount) + }) + } + s.group[user.ke].cloudDiskUse = user.cloudDiskUse + callback() + }) + } var loadAdminUsers = function(callback){ //get current disk used for each isolated account (admin user) on startup s.sqlQuery('SELECT * FROM Users WHERE details NOT LIKE ?',['%"sub"%'],function(err,users){ if(users && users[0]){ - var count = users.length - var countFinished = 0 - users.forEach(function(user){ - loadedAccounts.push(user.ke) - var userDetails = JSON.parse(user.details) - user.size = 0 - user.limit = userDetails.size - s.sqlQuery('SELECT * FROM Videos WHERE ke=? AND status!=?',[user.ke,0],function(err,videos){ - if(videos && videos[0]){ - videos.forEach(function(video){ - user.size += video.size - }) - } - s.loadGroup(user) - s.loadGroupApps(user) - ++countFinished - s.systemLog(user.mail+' : '+lang.startUpText0+' : '+videos.length,user.size) - s.systemLog(user.mail+' : '+lang.startUpText1,countFinished+'/'+count) - if(countFinished === count){ - callback() - } + var loadLocalDiskUse = function(callback){ + var count = users.length + var countFinished = 0 + users.forEach(function(user){ + loadedAccounts.push(user.ke) + loadDiskUseForUser(user,function(){ + s.loadGroup(user) + s.loadGroupApps(user) + ++countFinished + if(countFinished === count){ + callback() + } + }) + }) + } + var loadCloudDiskUse = function(callback){ + var count = users.length + var countFinished = 0 + users.forEach(function(user){ + loadCloudDiskUseForUser(user,function(){ + ++countFinished + if(countFinished === count){ + callback() + } + }) + }) + } + loadLocalDiskUse(function(){ + loadCloudDiskUse(function(){ + callback() }) }) }else{ diff --git a/libs/user.js b/libs/user.js index 12df22db..3f7ee469 100644 --- a/libs/user.js +++ b/libs/user.js @@ -2,12 +2,10 @@ var fs = require('fs'); var events = require('events'); var spawn = require('child_process').spawn; var exec = require('child_process').exec; -var request = require('request'); -var webdav = require("webdav-fs"); module.exports = function(s,config){ - s.purgeDiskForGroup = function(e,video){ + s.purgeDiskForGroup = function(e){ if(s.group[e.ke].diskUsedEmitter){ - s.group[e.ke].diskUsedEmitter.emit('purge',video) + s.group[e.ke].diskUsedEmitter.emit('purge') } } s.setDiskUsedForGroup = function(e,bytes){ @@ -16,6 +14,17 @@ module.exports = function(s,config){ s.group[e.ke].diskUsedEmitter.emit('set',bytes) } } + s.purgeCloudDiskForGroup = function(e,storageType){ + if(s.group[e.ke].diskUsedEmitter){ + s.group[e.ke].diskUsedEmitter.emit('purgeCloud',storageType) + } + } + s.setCloudDiskUsedForGroup = function(e,usage){ + //`bytes` will be used as the value to add or substract + if(s.group[e.ke].diskUsedEmitter){ + s.group[e.ke].diskUsedEmitter.emit('setCloud',usage) + } + } s.sendDiskUsedAmountToClients = function(e){ //send the amount used disk space to connected users if(s.group[e.ke]&&s.group[e.ke].init){ @@ -29,7 +38,6 @@ module.exports = function(s,config){ s.sqlQuery('INSERT INTO Logs (ke,mid,info) VALUES (?,?,?)',[e.ke,e.mid,s.s(x)]); } s.tx({f:'log',ke:e.ke,mid:e.mid,log:x,time:s.timeObject()},'GRPLOG_'+e.ke); - // s.systemLog('s.log : ',{f:'log',ke:e.ke,mid:e.mid,log:x,time:s.timeObject()},'GRP_'+e.ke) } s.loadGroup = function(e){ if(!s.group[e.ke]){ @@ -49,7 +57,29 @@ module.exports = function(s,config){ //emit the changes to connected users s.sendDiskUsedAmountToClients(e) } + s.loadGroupAppExtensions = [] + s.loadGroupAppExtender = function(callback){ + s.loadGroupAppExtensions.push(callback) + } + s.unloadGroupAppExtensions = [] + s.unloadGroupAppExtender = function(callback){ + s.unloadGroupAppExtensions.push(callback) + } + s.cloudDisksLoaded = [] + s.cloudDisksLoader = function(storageType){ + s.cloudDisksLoaded.push(storageType) + } + s.onAccountSaveExtensions = [] + s.onAccountSave = function(callback){ + s.onAccountSaveExtensions.push(callback) + } + s.beforeAccountSaveExtensions = [] + s.beforeAccountSave = function(callback){ + s.beforeAccountSaveExtensions.push(callback) + } + s.cloudDiskUseStartupExtensions = {} s.loadGroupApps = function(e){ + // e = user if(!s.group[e.ke].init){ s.group[e.ke].init={}; } @@ -57,65 +87,73 @@ module.exports = function(s,config){ if(r&&r[0]){ r=r[0]; ar=JSON.parse(r.details); - //owncloud/webdav - if(!s.group[e.ke].webdav && - ar.webdav_user&& - ar.webdav_user!==''&& - ar.webdav_pass&& - ar.webdav_pass!==''&& - ar.webdav_url&& - ar.webdav_url!=='' - ){ - if(!ar.webdav_dir||ar.webdav_dir===''){ - ar.webdav_dir='/' - } - ar.webdav_dir = s.checkCorrectPathEnding(ar.webdav_dir) - s.group[e.ke].webdav = webdav( - ar.webdav_url, - ar.webdav_user, - ar.webdav_pass - ) - } - //Amazon S3 - if(!s.group[e.ke].aws && - !s.group[e.ke].aws_s3 && - ar.aws_s3 !== '0' && - ar.aws_accessKeyId !== ''&& - ar.aws_secretAccessKey && - ar.aws_secretAccessKey !== ''&& - ar.aws_region && - ar.aws_region !== ''&& - ar.aws_s3_bucket !== '' - ){ - if(!ar.aws_s3_dir || ar.aws_s3_dir === '/'){ - ar.aws_s3_dir = '' - } - if(ar.aws_s3_dir !== ''){ - ar.aws_s3_dir = s.checkCorrectPathEnding(ar.aws_s3_dir) - } - s.group[e.ke].aws = new require("aws-sdk") - s.group[e.ke].aws.config = new s.group[e.ke].aws.Config({ - accessKeyId: ar.aws_accessKeyId, - secretAccessKey: ar.aws_secretAccessKey, - region: ar.aws_region - }) - s.group[e.ke].aws_s3 = new s.group[e.ke].aws.S3(); - } - //discordbot - if(!s.group[e.ke].discordBot && - config.discordBot === true && - ar.discordbot === '1' && - ar.discordbot_token !== '' - ){ - s.group[e.ke].discordBot = new Discord.Client() - s.group[e.ke].discordBot.on('ready', () => { - console.log(`${r.mail} : Discord Bot Logged in as ${s.group[e.ke].discordBot.user.tag}!`) - }) - s.group[e.ke].discordBot.login(ar.discordbot_token) - } + //load extenders + s.loadGroupAppExtensions.forEach(function(extender){ + extender(r) + }) //disk Used Emitter if(!s.group[e.ke].diskUsedEmitter){ s.group[e.ke].diskUsedEmitter = new events.EventEmitter() + s.group[e.ke].diskUsedEmitter.on('setCloud',function(currentChange){ + var amount = currentChange.amount + var storageType = currentChange.storageType + var cloudDisk = s.group[e.ke].cloudDiskUse[storageType] + //validate current values + if(!cloudDisk.usedSpace){ + cloudDisk.usedSpace = 0 + }else{ + cloudDisk.usedSpace = parseFloat(cloudDisk.usedSpace) + } + if(cloudDisk.usedSpace < 0 || isNaN(cloudDisk.usedSpace)){ + cloudDisk.usedSpace = 0 + } + //change global size value + cloudDisk.usedSpace = cloudDisk.usedSpace + amount + }) + s.group[e.ke].diskUsedEmitter.on('purgeCloud',function(storageType){ + if(config.cron.deleteOverMax === true){ + //set queue processor + var finish=function(){ + // s.sendDiskUsedAmountToClients(e) + } + var deleteVideos = function(){ + //run purge command + var cloudDisk = s.group[e.ke].cloudDiskUse[storageType] + if(cloudDisk.sizeLimitCheck && cloudDisk.usedSpace > (cloudDisk.sizeLimit*config.cron.deleteOverMaxOffset)){ + s.sqlQuery('SELECT * FROM `Cloud Videos` WHERE status != 0 AND ke=? AND details LIKE \'%"type":"'+storageType+'"%\' ORDER BY `time` ASC LIMIT 2',[e.ke],function(err,videos){ + var videosToDelete = [] + var queryValues = [e.ke] + if(!videos)return console.log(err) + videos.forEach(function(video){ + video.dir = s.getVideoDirectory(video) + s.formattedTime(video.time) + '.' + video.ext + videosToDelete.push('(mid=? AND `time`=?)') + queryValues.push(video.mid) + queryValues.push(video.time) + s.setCloudDiskUsedForGroup(e,{ + amount : -(video.size/1000000), + storageType : storageType + }) + s.deleteVideoFromCloudExtensionsRunner(e,storageType,video) + }) + if(videosToDelete.length > 0){ + videosToDelete = videosToDelete.join(' OR ') + s.sqlQuery('DELETE FROM `Cloud Videos` WHERE ke =? AND ('+videosToDelete+')',queryValues,function(){ + deleteVideos() + }) + }else{ + finish() + } + }) + }else{ + finish() + } + } + deleteVideos() + }else{ + // s.sendDiskUsedAmountToClients(e) + } + }) + //s.setDiskUsedForGroup s.group[e.ke].diskUsedEmitter.on('set',function(currentChange){ //validate current values if(!s.group[e.ke].usedSpace){ @@ -131,30 +169,39 @@ module.exports = function(s,config){ //remove value just used from queue s.sendDiskUsedAmountToClients(e) }) - s.group[e.ke].diskUsedEmitter.on('purge',function(currentPurge){ - s.setDiskUsedForGroup(e,currentPurge.filesizeMB) - if(config.cron.deleteOverMax===true){ + s.group[e.ke].diskUsedEmitter.on('purge',function(){ + if(config.cron.deleteOverMax === true){ //set queue processor var finish=function(){ s.sendDiskUsedAmountToClients(e) } var deleteVideos = function(){ //run purge command - if(s.group[e.ke].usedSpace>(s.group[e.ke].sizeLimit*config.cron.deleteOverMaxOffset)){ - s.sqlQuery('SELECT * FROM Videos WHERE status != 0 AND details NOT LIKE \'%"archived":"1"%\' AND ke=? ORDER BY `time` ASC LIMIT 2',[e.ke],function(err,evs){ - k.del=[];k.ar=[e.ke]; - if(!evs)return console.log(err) - evs.forEach(function(ev){ - ev.dir=s.getVideoDirectory(ev)+s.formattedTime(ev.time)+'.'+ev.ext; - k.del.push('(mid=? AND `time`=?)'); - k.ar.push(ev.mid),k.ar.push(ev.time); - s.file('delete',ev.dir); - s.setDiskUsedForGroup(e,-(ev.size/1000000)) - s.tx({f:'video_delete',ff:'over_max',filename:s.formattedTime(ev.time)+'.'+ev.ext,mid:ev.mid,ke:ev.ke,time:ev.time,end:s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss')},'GRP_'+e.ke); - }); - if(k.del.length>0){ - k.qu=k.del.join(' OR '); - s.sqlQuery('DELETE FROM Videos WHERE ke =? AND ('+k.qu+')',k.ar,function(){ + if(s.group[e.ke].usedSpace > (s.group[e.ke].sizeLimit*config.cron.deleteOverMaxOffset)){ + s.sqlQuery('SELECT * FROM Videos WHERE status != 0 AND details NOT LIKE \'%"archived":"1"%\' AND ke=? ORDER BY `time` ASC LIMIT 2',[e.ke],function(err,videos){ + var videosToDelete = [] + var queryValues = [e.ke] + if(!videos)return console.log(err) + videos.forEach(function(video){ + video.dir = s.getVideoDirectory(video) + s.formattedTime(video.time) + '.' + video.ext + videosToDelete.push('(mid=? AND `time`=?)') + queryValues.push(video.mid) + queryValues.push(video.time) + s.file('delete',video.dir) + s.setDiskUsedForGroup(e,-(video.size/1000000)) + s.tx({ + f: 'video_delete', + ff: 'over_max', + filename: s.formattedTime(video.time)+'.'+video.ext, + mid: video.mid, + ke: video.ke, + time: video.time, + end: s.formattedTime(new Date,'YYYY-MM-DD HH:mm:ss') + },'GRP_'+e.ke) + }) + if(videosToDelete.length > 0){ + videosToDelete = videosToDelete.join(' OR ') + s.sqlQuery('DELETE FROM Videos WHERE ke =? AND ('+videosToDelete+')',queryValues,function(){ deleteVideos() }) }else{ diff --git a/libs/videos.js b/libs/videos.js index dad6fbcd..dfe947d0 100644 --- a/libs/videos.js +++ b/libs/videos.js @@ -45,123 +45,12 @@ module.exports = function(s,config,lang){ v.details = details }) } - s.uploadVideoToWebDav = function(e,k){ - //e = video object - //k = temporary values - if(!k)k={}; - //cloud saver - webdav - var wfs = s.group[e.ke].webdav - if(wfs && s.group[e.ke].init.use_webdav !== '0' && s.group[e.ke].init.webdav_save === "1"){ - var webdavUploadDir = s.group[e.ke].init.webdav_dir+e.ke+'/'+e.mid+'/' - var startWebDavUpload = function(){ - s.group[e.ke].mon[e.id].webdavDirExist = true - var wfsWriteStream = - fs.createReadStream(k.dir + k.filename).pipe(wfs.createWriteStream(webdavUploadDir + k.filename)) - if(s.group[e.ke].init.webdav_log === '1'){ - var webdavRemoteUrl = s.addUserPassToUrl(s.checkCorrectPathEnding(s.group[e.ke].init.webdav_url),s.group[e.ke].init.webdav_user,s.group[e.ke].init.webdav_pass) + s.group[e.ke].init.webdav_dir + e.ke + '/'+e.mid+'/'+k.filename - var save = [ - e.mid, - e.ke, - k.startTime, - 1, - s.s({ - type : 'webdav' - }), - k.filesize, - k.endTime, - webdavRemoteUrl - ] - s.sqlQuery('INSERT INTO `Cloud Videos` (mid,ke,time,status,details,size,end,href) VALUES (?,?,?,?,?,?,?,?)',save) - } - } - if(s.group[e.ke].mon[e.id].webdavDirExist !== true){ - //check if webdav dir exist - var parentPoint = 0 - var webDavParentz = webdavUploadDir.split('/') - var webDavParents = [] - webDavParentz.forEach(function(v){ - if(v && v !== '')webDavParents.push(v) - }) - var stitchPieces = './' - var lastParentCheck = function(){ - ++parentPoint - if(parentPoint === webDavParents.length){ - startWebDavUpload() - } - checkPathPiece(webDavParents[parentPoint]) - } - var checkPathPiece = function(pathPiece){ - if(pathPiece && pathPiece !== ''){ - stitchPieces += pathPiece + '/' - wfs.stat(stitchPieces, function(error, stats) { - if(error){ - reply = { - status : error.status, - msg : lang.WebdavErrorTextTryCreatingDir, - dir : stitchPieces, - } - s.log(e,{type:lang['Webdav Error'],msg:reply}) - wfs.mkdir(stitchPieces, function(error) { - if(error){ - reply = { - status : error.status, - msg : lang.WebdavErrorTextCreatingDir, - dir : stitchPieces, - } - s.log(e,{type:lang['Webdav Error'],msg:reply}) - }else{ - lastParentCheck() - } - }) - }else{ - lastParentCheck() - } - }) - }else{ - ++parentPoint - } - } - checkPathPiece(webDavParents[0]) - }else{ - startWebDavUpload() - } - } - } - s.uploadVideoToAmazonS3 = function(e,k){ - //e = video object - //k = temporary values - if(!k)k={}; - //cloud saver - amazon s3 - if(s.group[e.ke].aws_s3 && s.group[e.ke].init.use_aws_s3 !== '0' && s.group[e.ke].init.aws_s3_save === '1'){ - var fileStream = fs.createReadStream(k.dir+k.filename); - fileStream.on('error', function (err) { - console.error(err) - }) - s.group[e.ke].aws_s3.upload({ - Bucket: s.group[e.ke].init.aws_s3_bucket, - Key: s.group[e.ke].init.aws_s3_dir+e.ke+'/'+e.mid+'/'+k.filename, - Body:fileStream, - ACL:'public-read' - },function(err,data){ - if(err){ - s.log(e,{type:lang['Amazon S3 Upload Error'],msg:err}) - } - if(s.group[e.ke].init.aws_s3_log === '1' && data && data.Location){ - var save = [ - e.mid, - e.ke, - k.startTime, - 1, - '{}', - k.filesize, - k.endTime, - data.Location - ] - s.sqlQuery('INSERT INTO `Cloud Videos` (mid,ke,time,status,details,size,end,href) VALUES (?,?,?,?,?,?,?,?)',save) - } - }) - } + //extender for "s.insertCompletedVideo" + s.insertCompletedVideoExtensions = [] + s.insertCompletedVideoExtender = function(callback){ + s.insertCompletedVideoExtensions.push(callback) } + //on video completion s.insertCompletedVideo = function(e,k){ //e = video object //k = temporary values @@ -246,8 +135,9 @@ module.exports = function(s,config,lang){ end:k.endTime },'GRP_'+e.ke,'video_view'); } - s.uploadVideoToWebDav(e,k) - s.uploadVideoToAmazonS3(e,k) + s.insertCompletedVideoExtensions.forEach(function(extender){ + extender(e,k) + }) k.details = {} if(e.details&&e.details.dir&&e.details.dir!==''){ k.details.dir = e.details.dir @@ -264,8 +154,10 @@ module.exports = function(s,config,lang){ k.endTime, ] s.sqlQuery('INSERT INTO Videos (mid,ke,time,ext,status,details,size,end) VALUES (?,?,?,?,?,?,?,?)',save) + //purge over max + s.purgeDiskForGroup(e) //send new diskUsage values - s.purgeDiskForGroup(e,k) + s.setDiskUsedForGroup(e,k.filesizeMB) } } } @@ -308,10 +200,38 @@ module.exports = function(s,config,lang){ } }) } + s.deleteVideoFromCloudExtensions = {} + s.deleteVideoFromCloudExtensionsRunner = function(e,storageType,video){ + // e = user + if(!storageType){ + var videoDetails = JSON.parse(r.details) + videoDetails.type = videoDetails.type || 's3' + } + if(s.deleteVideoFromCloudExtensions[storageType]){ + s.deleteVideoFromCloudExtensions[storageType](e,video,function(){ + s.tx({ + f: 'video_delete_cloud', + mid: e.mid, + ke: e.ke, + time: e.time, + end: e.end + },'GRP_'+e.ke); + }) + } + } s.deleteVideoFromCloud = function(e){ //e = video object - s.sqlQuery('DELETE FROM `Cloud Videos` WHERE `mid`=? AND `ke`=? AND `time`=?',[e.id,e.ke,new Date(e.time)],function(){ - s.tx({f:'video_delete_cloud',mid:e.mid,ke:e.ke,time:e.time,end:e.end},'GRP_'+e.ke); + var videoSelector = [e.id,e.ke,new Date(e.time)] + s.sqlQuery('SELECT * FROM `Cloud Videos` WHERE `mid`=? AND `ke`=? AND `time`=?',videoSelector,function(err,r){ + if(r&&r[0]){ + r = r[0] + s.sqlQuery('DELETE FROM `Cloud Videos` WHERE `mid`=? AND `ke`=? AND `time`=?',videoSelector,function(){ + s.deleteVideoFromCloudExtensionsRunner(e,r) + }) + }else{ +// console.log('Delete Failed',e) +// console.error(err) + } }) } } diff --git a/libs/webServerPaths.js b/libs/webServerPaths.js index 40f1ad52..02846645 100644 --- a/libs/webServerPaths.js +++ b/libs/webServerPaths.js @@ -84,9 +84,9 @@ module.exports = function(s,config,lang,app){ delete(s.api[req.params.auth]); delete(s.group[req.params.ke].users[req.params.auth]); s.sqlQuery("UPDATE Users SET auth=? WHERE auth=? AND ke=? AND uid=?",['',req.params.auth,req.params.ke,req.params.id]) - res.end(s.s({ok:true,msg:'You have been logged out, session key is now inactive.'})) + res.end(s.prettyPrint({ok:true,msg:'You have been logged out, session key is now inactive.'})) }else{ - res.end(s.s({ok:false,msg:'This group key does not exist or this user is not logged in.'})) + res.end(s.prettyPrint({ok:false,msg:'This group key does not exist or this user is not logged in.'})) } }); //main page @@ -132,7 +132,7 @@ module.exports = function(s,config,lang,app){ }else{ req.ret.msg=user.lang.updateKeyText2; } - res.end(s.s(req.ret)); + res.end(s.prettyPrint(req.ret)); } s.auth(req.params,req.fn,res,req); }); @@ -144,7 +144,7 @@ module.exports = function(s,config,lang,app){ s.auth(req.params,function(user){ req.ret.ok=true req.ret.user=user - res.end(s.s(req.ret)); + res.end(s.prettyPrint(req.ret)); },res,req); }) //register function @@ -170,7 +170,7 @@ module.exports = function(s,config,lang,app){ s.sqlQuery('INSERT INTO Users (ke,uid,mail,pass,details) VALUES (?,?,?,?,?)',[req.params.ke,req.gid,req.body.mail,s.createHash(req.body.pass),req.body.details]) s.tx({f:'add_sub_account',details:req.body.details,ke:req.params.ke,uid:req.gid,mail:req.body.mail},'ADM_'+req.params.ke); } - res.end(s.s(req.resp)); + res.end(s.prettyPrint(req.resp)); }) }else{ req.resp.msg=user.lang['Passwords Don\'t Match']; @@ -182,7 +182,7 @@ module.exports = function(s,config,lang,app){ req.resp.msg=user.lang['Not an Administrator Account']; } if(req.resp.msg){ - res.end(s.s(req.resp)); + res.end(s.prettyPrint(req.resp)); } }) },res,req); @@ -202,7 +202,7 @@ module.exports = function(s,config,lang,app){ // brute check if(s.failedLoginAttempts[req.body.mail] && s.failedLoginAttempts[req.body.mail].failCount >= 5){ if(req.query.json=='true'){ - res.end(s.s({ok:false})) + res.end(s.prettyPrint({ok:false})) }else{ res.render(config.renderPaths.index,{ failedLogin:true, @@ -230,7 +230,7 @@ module.exports = function(s,config,lang,app){ delete(data.config) data.ok=true; res.setHeader('Content-Type', 'application/json'); - res.end(s.s(data)) + res.end(s.prettyPrint(data)) }else{ data.originalURL = s.getOriginalUrl(req) data.screen=req.params.screen @@ -262,7 +262,7 @@ module.exports = function(s,config,lang,app){ // check if JSON if(req.query.json=='true'){ res.setHeader('Content-Type', 'application/json'); - res.end(s.s({ok:false})) + res.end(s.prettyPrint({ok:false})) }else{ res.render(config.renderPaths.index,{ failedLogin:true, @@ -556,7 +556,7 @@ module.exports = function(s,config,lang,app){ } if(!req.details.acceptedMachines[req.body.machineID]){ req.details.acceptedMachines[req.body.machineID]={} - s.sqlQuery("UPDATE Users SET details=? WHERE ke=? AND uid=?",[s.s(req.details),req.body.ke,req.body.id]) + s.sqlQuery("UPDATE Users SET details=? WHERE ke=? AND uid=?",[s.prettyPrint(req.details),req.body.ke,req.body.id]) } } req.body.function = s.factorAuth[req.body.ke][req.body.id].function @@ -582,7 +582,7 @@ module.exports = function(s,config,lang,app){ clearTimeout(s.failedLoginAttempts[user.mail].timeout) delete(s.failedLoginAttempts[user.mail]) } - res.end(s.s({ok:true})) + res.end(s.prettyPrint({ok:true})) }) }) // Get HLS stream (m3u8) @@ -661,7 +661,7 @@ module.exports = function(s,config,lang,app){ }) }else{ res.setHeader('Content-Type', 'application/json'); - res.end(s.s({ok:false,msg:'FLV not started or not ready'})) + res.end(s.prettyPrint({ok:false,msg:'FLV not started or not ready'})) } },res,req) },res,req) @@ -904,7 +904,7 @@ module.exports = function(s,config,lang,app){ res.header("Access-Control-Allow-Origin",req.headers.origin); req.fn=function(user){ if(user.permissions.get_monitors==="0"){ - res.end(s.s([])) + res.end(s.prettyPrint([])) return } if(!req.params.ke){ @@ -1005,7 +1005,7 @@ module.exports = function(s,config,lang,app){ res.end(m3u8) }else{ if(tvChannelMonitors.length===1){tvChannelMonitors=tvChannelMonitors[0];} - res.end(s.s(tvChannelMonitors)); + res.end(s.prettyPrint(tvChannelMonitors)); } }) } @@ -1018,7 +1018,7 @@ module.exports = function(s,config,lang,app){ res.header("Access-Control-Allow-Origin",req.headers.origin); req.fn=function(user){ if(user.permissions.get_monitors==="0"){ - res.end(s.s([])) + res.end(s.prettyPrint([])) return } req.sql='SELECT * FROM Monitors WHERE ke=?';req.ar=[req.params.ke]; @@ -1092,7 +1092,7 @@ module.exports = function(s,config,lang,app){ } }) if(r.length===1){r=r[0];} - res.end(s.s(r)); + res.end(s.prettyPrint(r)); }) } s.auth(req.params,req.fn,res,req); @@ -1112,7 +1112,7 @@ module.exports = function(s,config,lang,app){ user.permissions.watch_videos==="0" || hasRestrictions && (!user.details.video_view || user.details.video_view.indexOf(req.params.id)===-1) ){ - res.end(s.s([])) + res.end(s.prettyPrint([])) return } var origURL = req.originalUrl.split('/') @@ -1193,7 +1193,7 @@ module.exports = function(s,config,lang,app){ } s.sqlQuery(req.sql,req.ar,function(err,r){ if(!r){ - res.end(s.s({total:0,limit:req.query.limit,skip:0,videos:[]})); + res.end(s.prettyPrint({total:0,limit:req.query.limit,skip:0,videos:[]})); return } s.sqlQuery(req.count_sql,req.count_ar,function(err,count){ @@ -1209,7 +1209,7 @@ module.exports = function(s,config,lang,app){ req.skip=0 req.query.limit=parseInt(req.query.limit) } - res.end(s.s({isUTC:config.useUTC,total:count[0]['COUNT(*)'],limit:req.query.limit,skip:req.skip,videos:r})); + res.end(s.prettyPrint({isUTC:config.useUTC,total:count[0]['COUNT(*)'],limit:req.query.limit,skip:req.skip,videos:r})); }) }) },res,req); @@ -1221,7 +1221,7 @@ module.exports = function(s,config,lang,app){ res.header("Access-Control-Allow-Origin",req.headers.origin); s.auth(req.params,function(user){ if(user.permissions.watch_videos==="0"||user.details.sub&&user.details.allmonitors!=='1'&&user.details.video_view.indexOf(req.params.id)===-1){ - res.end(s.s([])) + res.end(s.prettyPrint([])) return } req.sql='SELECT * FROM Events WHERE ke=?';req.ar=[req.params.ke]; @@ -1259,14 +1259,14 @@ module.exports = function(s,config,lang,app){ s.sqlQuery(req.sql,req.ar,function(err,r){ if(err){ err.sql=req.sql; - res.end(s.s(err)); + res.end(s.prettyPrint(err)); return } if(!r){r=[]} r.forEach(function(v,n){ r[n].details=JSON.parse(v.details); }) - res.end(s.s(r)); + res.end(s.prettyPrint(r)); }) },res,req); }); @@ -1277,7 +1277,7 @@ module.exports = function(s,config,lang,app){ res.header("Access-Control-Allow-Origin",req.headers.origin); s.auth(req.params,function(user){ if(user.permissions.get_logs==="0" || user.details.sub && user.details.view_logs !== '1'){ - res.end(s.s([])) + res.end(s.prettyPrint([])) return } req.sql='SELECT * FROM Logs WHERE ke=?';req.ar=[req.params.ke]; @@ -1322,14 +1322,14 @@ module.exports = function(s,config,lang,app){ s.sqlQuery(req.sql,req.ar,function(err,r){ if(err){ err.sql=req.sql; - res.end(s.s(err)); + res.end(s.prettyPrint(err)); return } if(!r){r=[]} r.forEach(function(v,n){ r[n].info=JSON.parse(v.info) }) - res.end(s.s(r)); + res.end(s.prettyPrint(r)); }) },res,req); }); @@ -1340,7 +1340,7 @@ module.exports = function(s,config,lang,app){ res.header("Access-Control-Allow-Origin",req.headers.origin); req.fn=function(user){ if(user.permissions.get_monitors==="0"){ - res.end(s.s([])) + res.end(s.prettyPrint([])) return } req.sql='SELECT * FROM Monitors WHERE ke=?';req.ar=[req.params.ke]; @@ -1363,7 +1363,7 @@ module.exports = function(s,config,lang,app){ }else{ req.ar=[]; } - res.end(s.s(req.ar)); + res.end(s.prettyPrint(req.ar)); }) } s.auth(req.params,req.fn,res,req); @@ -1378,7 +1378,7 @@ module.exports = function(s,config,lang,app){ if(req.params.f !== 'delete'){ if(!req.body.data&&!req.query.data){ req.ret.msg='No Monitor Data found.' - res.end(s.s(req.ret)) + res.end(s.prettyPrint(req.ret)) return } try{ @@ -1390,7 +1390,7 @@ module.exports = function(s,config,lang,app){ }catch(er){ if(!req.monitor){ req.ret.msg=user.lang.monitorEditText1; - res.end(s.s(req.ret)) + res.end(s.prettyPrint(req.ret)) } return } @@ -1406,7 +1406,7 @@ module.exports = function(s,config,lang,app){ }catch(er){ if(!req.monitor.details||!req.monitor.details.stream_type){ req.ret.msg=user.lang.monitorEditText2; - res.end(s.s(req.ret)) + res.end(s.prettyPrint(req.ret)) return }else{ req.monitor.details=JSON.stringify(req.monitor.details) @@ -1463,15 +1463,15 @@ module.exports = function(s,config,lang,app){ s.tx(req.tx,'STR_'+req.monitor.ke); }; s.tx(req.tx,'GRP_'+req.monitor.ke); - res.end(s.s(req.ret)) + res.end(s.prettyPrint(req.ret)) }) }else{ req.ret.msg=user.lang.monitorEditText1; - res.end(s.s(req.ret)) + res.end(s.prettyPrint(req.ret)) } }else{ req.ret.msg=user.lang['Not Permitted']; - res.end(s.s(req.ret)) + res.end(s.prettyPrint(req.ret)) } }else{ if(!user.details.sub || user.details.allmonitors === '1' || user.details.monitor_edit.indexOf(req.params.id) > -1 || hasRestrictions && user.details.monitor_create === '1'){ @@ -1506,10 +1506,10 @@ module.exports = function(s,config,lang,app){ } req.ret.ok=true; req.ret.msg='Monitor Deleted by user : '+user.uid - res.end(s.s(req.ret)) + res.end(s.prettyPrint(req.ret)) }else{ req.ret.msg=user.lang['Not Permitted']; - res.end(s.s(req.ret)) + res.end(s.prettyPrint(req.ret)) } } }) @@ -1523,10 +1523,10 @@ module.exports = function(s,config,lang,app){ res.end(user.lang['Not Permitted']) return } - if(req.params.f===''){req.ret.msg=user.lang.monitorGetText1;res.end(s.s(req.ret));return} + if(req.params.f===''){req.ret.msg=user.lang.monitorGetText1;res.end(s.prettyPrint(req.ret));return} if(req.params.f!=='stop'&&req.params.f!=='start'&&req.params.f!=='record'){ req.ret.msg='Mode not recognized.'; - res.end(s.s(req.ret)); + res.end(s.prettyPrint(req.ret)); return; } s.sqlQuery('SELECT * FROM Monitors WHERE ke=? AND mid=?',[req.params.ke,req.params.id],function(err,r){ @@ -1603,7 +1603,7 @@ module.exports = function(s,config,lang,app){ }else{ req.ret.msg=user.lang['Monitor or Key does not exist.']; } - res.end(s.s(req.ret)); + res.end(s.prettyPrint(req.ret)); }) },res,req); }) @@ -1634,7 +1634,7 @@ module.exports = function(s,config,lang,app){ v.href='/'+req.params.auth+'/fileBin/'+req.params.ke+'/'+req.params.id+'/'+v.details.year+'/'+v.details.month+'/'+v.details.day+'/'+v.name; }) } - res.end(s.s(r)); + res.end(s.prettyPrint(r)); }) } s.auth(req.params,req.fn,res,req); @@ -1673,7 +1673,7 @@ module.exports = function(s,config,lang,app){ res.header("Access-Control-Allow-Origin",req.headers.origin); var failed = function(resp){ res.setHeader('Content-Type', 'application/json'); - res.end(s.s(resp)) + res.end(s.prettyPrint(resp)) } if(req.query.videos && req.query.videos !== ''){ s.auth(req.params,function(user){ @@ -1857,7 +1857,7 @@ module.exports = function(s,config,lang,app){ res.setHeader('Content-Type', 'application/json'); s.auth(req.params,function(user){ s.log(req.params,{type:'Test',msg:'Hook Test'}) - res.end(s.s({ok:true})) + res.end(s.prettyPrint({ok:true})) },res,req); }) //control trigger @@ -1866,7 +1866,7 @@ module.exports = function(s,config,lang,app){ res.header("Access-Control-Allow-Origin",req.headers.origin); s.auth(req.params,function(user){ s.camera('control',req.params,function(resp){ - res.end(s.s(resp)) + res.end(s.prettyPrint(resp)) }); },res,req); }) @@ -1942,7 +1942,7 @@ module.exports = function(s,config,lang,app){ }else{ req.ret.msg=user.lang['No such file']; } - res.end(s.s(req.ret)); + res.end(s.prettyPrint(req.ret)); }) },res,req); }) @@ -2058,12 +2058,12 @@ module.exports = function(s,config,lang,app){ default: if(!req.query.url){ req.ret.error = 'Missing URL' - res.end(s.s(req.ret)); + res.end(s.prettyPrint(req.ret)); return } if(user.ffprobe){ req.ret.error = 'Account is already probing' - res.end(s.s(req.ret)); + res.end(s.prettyPrint(req.ret)); return } user.ffprobe=1; @@ -2084,7 +2084,7 @@ module.exports = function(s,config,lang,app){ req.ret.result = stdout+stderr } req.ret.probe = req.probeCommand - res.end(s.s(req.ret)); + res.end(s.prettyPrint(req.ret)); }) break; } @@ -2100,7 +2100,7 @@ module.exports = function(s,config,lang,app){ response.ok = false response.msg = msg response.error = error - res.end(s.s(response)) + res.end(s.prettyPrint(response)) } var actionCallback = function(onvifActionResponse){ response.ok = true @@ -2110,7 +2110,7 @@ module.exports = function(s,config,lang,app){ response.responseFromDevice = onvifActionResponse } if(onvifActionResponse.soap)response.soap = onvifActionResponse.soap - res.end(s.s(response)) + res.end(s.prettyPrint(response)) } var isEmpty = function(obj) { for(var key in obj) { @@ -2128,10 +2128,10 @@ module.exports = function(s,config,lang,app){ }else if(command){ response.ok = true response.repsonseFromDevice = command - res.end(s.s(response)) + res.end(s.prettyPrint(response)) }else{ response.error = 'Big Errors, Please report it to Shinobi Development' - res.end(s.s(response)) + res.end(s.prettyPrint(response)) } } var action diff --git a/web/pages/blocks/settings.ejs b/web/pages/blocks/settings.ejs index 46a45b50..d1ecc9be 100644 --- a/web/pages/blocks/settings.ejs +++ b/web/pages/blocks/settings.ejs @@ -207,6 +207,19 @@ +