Merge branch 'storageareas' into zma_to_thread

This commit is contained in:
Isaac Connor 2018-01-01 16:38:54 -05:00
commit 834dfbfe0c
23 changed files with 447 additions and 288 deletions

3
.gitmodules vendored
View File

@ -2,3 +2,6 @@
path = web/api/app/Plugin/Crud
url = https://github.com/FriendsOfCake/crud.git
branch = 3.0
[submodule "web/api/app/Plugin/CakePHP-Enum-Behavior"]
path = web/api/app/Plugin/CakePHP-Enum-Behavior
url = https://github.com/asper/CakePHP-Enum-Behavior.git

View File

@ -213,7 +213,8 @@ CREATE TABLE `Events` (
KEY `MonitorId` (`MonitorId`),
KEY `StartTime` (`StartTime`),
KEY `Frames` (`Frames`),
KEY `Archived` (`Archived`)
KEY `Archived` (`Archived`),
KEY `EndTime_DiskSpace` (`EndTime`,`DiskSpace`)
) ENGINE=@ZM_MYSQL_ENGINE@;
--
@ -277,7 +278,7 @@ CREATE TABLE `Groups` (
--Table structure for table `Groups_Monitors`
--
DROP TABLE IF EXISTS `Groups_Monitors`
DROP TABLE IF EXISTS `Groups_Monitors`;
CREATE TABLE `Groups_Monitors` (
`Id` INT(10) unsigned NOT NULL auto_increment,
`GroupId` int(10) unsigned NOT NULL,
@ -640,6 +641,7 @@ CREATE TABLE `Storage` (
`Type` enum('local','s3fs') NOT NULL default 'local',
`DiskSpace` bigint unsigned default NULL,
`Scheme enum('Deep','Medium','Shallow') NOT NULL default 'Medium',
`ServerId` int(10) unsigned,
PRIMARY KEY (`Id`)
) ENGINE=@ZM_MYSQL_ENGINE@;
@ -668,7 +670,25 @@ insert into Users VALUES (NULL,'admin',password('admin'),'',1,'View','Edit','Edi
--
-- Add a sample filter to purge the oldest 100 events when the disk is 95% full
--
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',0,0,0,0,0,0,'',1,0,1,0);
`Id` int(10) unsigned NOT NULL auto_increment,
`Name` varchar(64) NOT NULL default '',
`Query` text NOT NULL,
`AutoArchive` tinyint(3) unsigned NOT NULL default '0',
`AutoVideo` tinyint(3) unsigned NOT NULL default '0',
`AutoUpload` tinyint(3) unsigned NOT NULL default '0',
`AutoEmail` tinyint(3) unsigned NOT NULL default '0',
`AutoMessage` tinyint(3) unsigned NOT NULL default '0',
`AutoExecute` tinyint(3) unsigned NOT NULL default '0',
`AutoExecuteCmd` tinytext,
`AutoDelete` tinyint(3) unsigned NOT NULL default '0',
`AutoMove` tinyint(3) unsigned NOT NULL default '0',
`AutoMoveTo` smallint(5) unsigned NOT NULL default 0,
`UpdateDiskSpace` tinyint(3) unsigned NOT NULL default '0',
`Background` tinyint(1) unsigned NOT NULL default '0',
`Concurrent` tinyint(1) unsigned NOT NULL default '0',
insert into Filters values (NULL,'PurgeWhenFull','{"sort_field":"Id","terms":[{"val":0,"attr":"Archived","op":"="},{"cnj":"and","val":95,"attr":"DiskPercent","op":">="}],"limit":100,"sort_asc":1}',0/*AutoArchive*/,0/*AutoVideo*/,0/*AutoUpload*/,0/*AutoEmail*/,0/*AutoMessage*/,0/*AutoExecute*/,'',1/*AutoDelete*/,0/*AutoMove*/,0/*MoveTo*/,0/*UpdateDiskSpace*/,1/*Background*/,0/*Concurrent*/);
insert into Filters values (NULL,'Update DiskSpace','{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}',0,0,0,0,0,0,'',0,0,0,1,1,0);
--
-- Add in some sample control protocol definitions

23
db/zm_update-1.31.18.sql Normal file
View File

@ -0,0 +1,23 @@
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = DATABASE()
AND table_name = 'Storage'
AND column_name = 'ServerId'
) > 0,
"SELECT 'Column ServerId already exists in Storage'",
"ALTER TABLE Storage ADD `ServerId` int(10) unsigned AFTER `Scheme`"
));
PREPARE stmt FROM @s;
EXECUTE stmt;
SET @s = (SELECT IF(
(SELECT COUNT(*) FROM Filters WHERE Name = 'Update DiskSpace'
AND Query = '{"terms":[{"attr":"DiskSpace","op":"IS","val":"NULL"}]}'
) > 0,
"SELECT 'Update Disk Space Filter already exists.'",
"INSERT INTO Filters (Name,Query,UpdateDiskSpace,Background) values ('Update DiskSpace','{\"terms\":[{\"attr\":\"DiskSpace\",\"op\":\"IS\",\"val\":\"NULL\"}]}',1,1)"
));
PREPARE stmt FROM @s;
EXECUTE stmt;

View File

@ -154,11 +154,21 @@ sub Path {
if ( ! $$event{Path} ) {
my $Storage = $event->Storage();
$$event{Path} = join('/', $Storage->Path(), $event->RelativePath() );
}
return $$event{Path};
}
sub RelativePath {
my $event = shift;
if ( @_ ) {
$$event{RelativePath} = $_[0];
}
if ( ! $$event{RelativePath} ) {
if ( $$event{Scheme} eq 'Deep' ) {
if ( $event->Time() ) {
$$event{Path} = join('/',
$Storage->Path(),
$$event{RelativePath} = join('/',
$event->{MonitorId},
strftime( '%y/%m/%d/%H/%M/%S',
localtime($event->Time())
@ -166,30 +176,28 @@ sub Path {
);
} else {
Error("Event $$event{Id} has no value for Time(), unable to determine path");
$$event{Path} = '';
$$event{RelativePath} = '';
}
} elsif ( $$event{Scheme} eq 'Medium' ) {
if ( $event->Time() ) {
$$event{Path} = join('/',
$Storage->Path(),
$$event{RelativePath} = join('/',
$event->{MonitorId},
strftime( '%Y-%m-%d', localtime($event->Time())),
$event->{Id},
);
} else {
Error("Event $$event{Id} has no value for Time(), unable to determine path");
$$event{Path} = '';
$$event{RelativePath} = '';
}
} else { # Shallow
$$event{Path} = join('/',
$Storage->Path(),
$$event{RelativePath} = join('/',
$event->{MonitorId},
$event->{Id},
);
} # end if Scheme
} # end if ! Path
return $$event{Path};
return $$event{RelativePath};
}
sub GenerateVideo {
@ -337,7 +345,7 @@ sub delete_files {
return;
}
Debug("Deleting files for Event $$event{Id} from $storage_path.");
my $link_path = $$event{MonitorId}."/*/*/*/.".$$event{Id};
my $link_path = $$event{MonitorId}.'/*/*/*/.'.$$event{Id};
#Debug( "LP1:$link_path" );
my @links = glob($link_path);
#Debug( "L:".$links[0].": $!" );
@ -371,7 +379,7 @@ sub delete_files {
}
} # end if links
} else {
my $command = "/bin/rm -rf ". $event->Path();
my $command = '/bin/rm -rf '. $storage_path . '/'. $event->RelativePath();
ZoneMinder::General::executeShellCommand( $command );
}
} # end sub delete_files

View File

@ -238,8 +238,13 @@ MAIN: while( $loop ) {
} elsif ( $$Storage{Scheme} eq 'Medium' ) {
foreach my $event_dir ( glob("$monitor_dir/*/*") ) {
next if ! -d $event_dir;
my $Event = $fs_events->{$event} = new ZoneMinder::Event();
$$Event{Id} = $event;
my ( $date, $event_id ) = $event_dir =~ /^$monitor_dir\/(\d{4}\-\d{2}\-\d{2})\/(\d\+)$/;
if ( ! $event_id ) {
Debug("Unable to parse date/event_id from $event_dir");
next;
}
my $Event = $fs_events->{$event_id} = new ZoneMinder::Event();
$$Event{Id} = $event_id;
$$Event{Path} = $event_dir;
$Event->MonitorId( $monitor_dir );
$Event->StorageId( $Storage->Id() );

View File

@ -1 +1 @@
1.31.17
1.31.18

View File

@ -70,6 +70,7 @@ Cache::config('default', array('engine' => 'Apc'));
*
*/
CakePlugin::load('Crud');
CakePlugin::load('CakePHP-Enum-Behavior');
/**
* You can attach event listeners to the request lifecycle as Dispatcher Filter. By default CakePHP bundles two filters:
@ -142,6 +143,27 @@ foreach( $configvals as $key => $value) {
Configure::write( $key, $value );
}
// For Human-readability, use ZM_SERVER_HOST or ZM_SERVER_NAME in zm.conf, and convert it here to a ZM_SERVER_ID
if ( ! defined('ZM_SERVER_ID') ) {
App::uses('ClassRegistry', 'Utility');
$ServerModel = ClassRegistry::init('Server');
if ( defined('ZM_SERVER_NAME') and ZM_SERVER_NAME ) {
$Server = $ServerModel->find( 'first', array( 'conditions'=>array('Name'=>ZM_SERVER_NAME) ) );
if ( ! $Server ) {
Error('Invalid Multi-Server configration detected. ZM_SERVER_NAME set to ' . ZM_SERVER_NAME . ' in zm.conf, but no corresponding entry found in Servers table.');
} else {
define( 'ZM_SERVER_ID', $Server['Server']['Id'] );
}
} else if ( defined('ZM_SERVER_HOST') and ZM_SERVER_HOST ) {
$Server = $ServerModel->find( 'first', array( 'conditions'=>array('Name'=>ZM_SERVER_HOST) ) );
if ( ! $Server ) {
Error('Invalid Multi-Server configration detected. ZM_SERVER_HOST set to ' . ZM_SERVER_HOST . ' in zm.conf, but no corresponding entry found in Servers table.');
} else {
define( 'ZM_SERVER_ID', $Server['Server']['Id'] );
}
}
}
function process_configfile($configFile) {
if ( is_readable( $configFile ) ) {
$configvals = array();

View File

@ -15,10 +15,13 @@ class MonitorsController extends AppController {
*/
public $components = array('Paginator', 'RequestHandler');
public function beforeRender() {
$this->set($this->Monitor->enumValues());
}
public function beforeFilter() {
parent::beforeFilter();
$canView = $this->Session->Read('monitorPermission');
if ($canView =='None') {
if ($canView == 'None') {
throw new UnauthorizedException(__('Insufficient Privileges'));
return;
}
@ -109,10 +112,9 @@ class MonitorsController extends AppController {
* @return void
*/
public function add() {
if ($this->request->is('post')) {
if ( $this->request->is('post') ) {
if ($this->Session->Read('systemPermission') != 'Edit')
{
if ( $this->Session->Read('systemPermission') != 'Edit' ) {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
@ -120,8 +122,15 @@ class MonitorsController extends AppController {
$this->Monitor->create();
if ($this->Monitor->save($this->request->data)) {
$this->daemonControl($this->Monitor->id, 'start');
return $this->flash(__('The monitor has been saved.'), array('action' => 'index'));
//return $this->flash(__('The monitor has been saved.'), array('action' => 'index'));
$message = 'Saved';
} else {
$message = 'Error';
}
$this->set(array(
'message' => $message,
'_serialize' => array('message')
));
}
}
@ -138,8 +147,7 @@ class MonitorsController extends AppController {
if (!$this->Monitor->exists($id)) {
throw new NotFoundException(__('Invalid monitor'));
}
if ($this->Session->Read('monitorPermission') != 'Edit')
{
if ($this->Session->Read('monitorPermission') != 'Edit') {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
@ -160,12 +168,11 @@ class MonitorsController extends AppController {
'conditions' => array('Id' => $id)
))['Monitor']['Function'];
// We don't pass the request data as the monitor object because it may be a subset of the full monitor array
if ( $func == 'None' ) {
$this->daemonControl( $this->Monitor->id, 'stop' );
} else {
$this->daemonControl( $this->Monitor->id, 'restart' );
}
if ( ( $func != 'None' ) and ( $this->Monitor->ServerId == ZM_SERVER_ID ) ) {
$this->daemonControl( $this->Monitor->id, 'start' );
}
} // end function edit
/**
* delete method
@ -179,8 +186,7 @@ class MonitorsController extends AppController {
if (!$this->Monitor->exists()) {
throw new NotFoundException(__('Invalid monitor'));
}
if ($this->Session->Read('systemPermission') != 'Edit')
{
if ($this->Session->Read('systemPermission') != 'Edit') {
throw new UnauthorizedException(__('Insufficient privileges'));
return;
}
@ -213,32 +219,29 @@ class MonitorsController extends AppController {
// expected format: http(s):/portal-api-url/monitors/alarm/id:M/command:C.json
// where M=monitorId
// where C=on|off|status
public function alarm()
{
public function alarm() {
$id = $this->request->params['named']['id'];
$cmd = strtolower($this->request->params['named']['command']);
if (!$this->Monitor->exists($id)) {
throw new NotFoundException(__('Invalid monitor'));
}
if ( $cmd != 'on' && $cmd != 'off' && $cmd != 'status')
{
if ( $cmd != 'on' && $cmd != 'off' && $cmd != 'status' ) {
throw new BadRequestException(__('Invalid command'));
}
$zm_path_bin = Configure::read('ZM_PATH_BIN');
switch ($cmd)
{
case "on":
switch ($cmd) {
case 'on':
$q = '-a';
$verbose = "-v";
$verbose = '-v';
break;
case "off":
$q = "-c";
$verbose = "-v";
case 'off':
$q = '-c';
$verbose = '-v';
break;
case "status":
$verbose = ""; // zmu has a bug - gives incorrect verbose output in this case
$q = "-s";
case 'status':
$verbose = ''; // zmu has a bug - gives incorrect verbose output in this case
$q = '-s';
break;
}
@ -253,11 +256,9 @@ class MonitorsController extends AppController {
$config = $this->Config->find('first', $options);
$zmAuthRelay = $config['Config']['Value'];
$auth="";
if ($zmOptAuth)
{
if ($zmAuthRelay == 'hashed')
{
$auth='';
if ( $zmOptAuth ) {
if ( $zmAuthRelay == 'hashed' ) {
$options = array('conditions' => array('Config.' . $this->Config->primaryKey => 'ZM_AUTH_HASH_SECRET'));
$config = $this->Config->find('first', $options);
$zmAuthHashSecret = $config['Config']['Value'];
@ -265,16 +266,12 @@ class MonitorsController extends AppController {
$time = localtime();
$ak = $zmAuthHashSecret.$this->Session->Read('username').$this->Session->Read('passwordHash').$time[2].$time[3].$time[4].$time[5];
$ak = md5($ak);
$auth = " -A ".$ak;
}
elseif ($zmAuthRelay == 'plain')
{
$auth = " -U " .$this->Session->Read('username')." -P ".$this->Session->Read('password');
$auth = ' -A '.$ak;
} else if ( $zmAuthRelay == 'plain' ) {
$auth = ' -U ' .$this->Session->Read('username').' -P '.$this->Session->Read('password');
}
elseif ($zmAuthRelay == 'none')
{
$auth = " -U " .$this->Session->Read('username');
} else if ( $zmAuthRelay == 'none' ) {
$auth = ' -U ' .$this->Session->Read('username');
}
}
@ -285,8 +282,6 @@ class MonitorsController extends AppController {
'status' => $status,
'_serialize' => array('status'),
));
}
// Check if a daemon is running for the monitor id
@ -308,9 +303,9 @@ class MonitorsController extends AppController {
// Pass -d for local, otherwise -m
if ($monitor[0]['Type'] == 'Local') {
$args = "-d ". $monitor[0]['Device'];
$args = '-d '. $monitor[0]['Device'];
} else {
$args = "-m ". $monitor[0]['Id'];
$args = '-m '. $monitor[0]['Id'];
}
// Build the command, and execute it
@ -346,9 +341,9 @@ class MonitorsController extends AppController {
}
if ($monitor['Type'] == 'Local') {
$args = "-d " . $monitor['Device'];
$args = '-d ' . $monitor['Device'];
} else {
$args = "-m " . $id;
$args = '-m ' . $id;
}
if ($monitor['Function'] == 'Monitor') {
@ -365,5 +360,4 @@ class MonitorsController extends AppController {
}
}
}
} // end class MonitorsController

View File

@ -86,10 +86,10 @@ class Monitor extends AppModel {
);
/**
* * hasMany associations
* *
* * @var array
* */
* hasMany associations
*
* @var array
*/
public $hasAndBelongsToMany = array(
'Group' => array(
'className' => 'Group',
@ -108,5 +108,16 @@ class Monitor extends AppModel {
'counterQuery' => ''
),
);
public $actsAs = array(
'CakePHP-Enum-Behavior.Enum' => array(
'Type' => array('Local','Remote','File','Ffmpeg','Libvlc','cURL'),
'Function' => array('None','Monitor','Modect','Record','Mocord','Nodect'),
'Orientation' => array('0','90','180','270','hori','vert'),
'OutputCodec' => array('h264','mjpeg','mpeg1','mpeg2'),
'OutputContainer' => array('auto','mp4','mkv'),
'DefaultView' => array('Events','Control'),
'Status' => array('Unknown','NotRunning','Running','NoSignal','Signal'),
)
);
}

@ -0,0 +1 @@
Subproject commit 7108489f218c54d36d235d3af91d6da2f8311237

View File

@ -0,0 +1,2 @@
echo json_encode($message);
echo json_encode($monitor);

View File

@ -0,0 +1,2 @@
$xml = Xml::fromArray(array('response' => $message));
echo $xml->asXML();

View File

@ -160,7 +160,16 @@ class Event {
public function getStreamSrc( $args=array(), $querySep='&' ) {
if ( $this->{'DefaultVideo'} and $args['mode'] != 'jpeg' ) {
return ( ZM_BASE_PATH != '/' ? ZM_BASE_PATH : '' ).'/index.php?view=view_video&eid='.$this->{'Id'};
$streamSrc = ZM_BASE_PROTOCOL.'://';
$Monitor = $this->Monitor();
if ( $Monitor->ServerId() ) {
$Server = $Monitor->Server();
$streamSrc .= $Server->Hostname();
} else {
$streamSrc .= $_SERVER['HTTP_HOST'];
}
$streamSrc .= ( ZM_BASE_PATH != '/' ? ZM_BASE_PATH : '' ).'/index.php?view=view_video&eid='.$this->{'Id'};
return $streamSrc;
}
$streamSrc = ZM_BASE_URL.ZM_PATH_ZMS;

View File

@ -295,8 +295,8 @@ private $control_fields = array(
}
return $filters;
}
public function save( $new_values = null ) {
public function save( $new_values = null ) {
if ( $new_values ) {
foreach ( $new_values as $k=>$v ) {
@ -304,8 +304,10 @@ private $control_fields = array(
}
}
$sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, array_keys( $this->defaults ) ) ) . ' WHERE Id=?';
$values = array_map( function($field){return $this->{$field};}, $this->fields );
$fields = array_keys( $this->defaults );
$sql = 'UPDATE Monitors SET '.implode(', ', array_map( function($field) {return $field.'=?';}, $fields ) ) . ' WHERE Id=?';
$values = array_map( function($field){return $this->{$field};}, $fields );
$values[] = $this->{'Id'};
dbQuery( $sql, $values );
} // end function save

View File

@ -70,15 +70,38 @@ class Storage {
Warning( "Unknown function call Storage->$fn from $file:$line" );
}
}
public static function find_all() {
$storage_areas = array();
$result = dbQuery( 'SELECT * FROM Storage ORDER BY Name');
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage' );
foreach ( $results as $row => $obj ) {
$storage_areas[] = $obj;
$storage_cache[$obj->Id()] = $obj;
public static function find_all( $parameters = null, $options = null ) {
$filters = array();
$sql = 'SELECT * FROM Storage ';
$values = array();
if ( $parameters ) {
$fields = array();
$sql .= 'WHERE ';
foreach ( $parameters as $field => $value ) {
if ( $value == null ) {
$fields[] = $field.' IS NULL';
} else if ( is_array( $value ) ) {
$func = function(){return '?';};
$fields[] = $field.' IN ('.implode(',', array_map( $func, $value ) ). ')';
$values += $value;
} else {
$fields[] = $field.'=?';
$values[] = $value;
}
return $storage_areas;
}
$sql .= implode(' AND ', $fields );
}
if ( $options and isset($options['order']) ) {
$sql .= ' ORDER BY ' . $options['order'];
}
$result = dbQuery($sql, $values);
$results = $result->fetchALL(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Storage');
foreach ( $results as $row => $obj ) {
$filters[] = $obj;
}
return $filters;
}
public function disk_usage_percent() {
$path = $this->Path();
@ -95,11 +118,8 @@ class Storage {
Error("disk_total_space returned false for " . $path );
return 0;
}
$free = disk_free_space( $path );
if ( ! $free ) {
Error("disk_free_space returned false for " . $path );
}
$usage = round(($total - $free) / $total * 100);
$used = $this->disk_used_space();
$usage = round( ($used / $total) * 100);
return $usage;
}
public function disk_total_space() {

View File

@ -1280,6 +1280,7 @@ function parseFilter( &$filter, $saveToSession=false, $querySep='&' ) {
$filter['sql'] .= ' not regexp '.$value;
break;
case '=[]' :
case 'IN' :
$filter['sql'] .= ' in ('.join( ',', $valueList ).')';
break;
case '![]' :

View File

@ -320,6 +320,9 @@ if ($reload == 'reload') ob_start();
}
$func = function($S){ return '<span title="'.human_filesize($S->disk_used_space()) . ' of ' . human_filesize($S->disk_total_space()).'">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; };
#$func = function($S){ return '<span title="">'.$S->Name() . ': ' . $S->disk_usage_percent().'%' . '</span>'; };
if ( count($storage_areas) >= 4 )
$storage_areas = Storage::find_all( array('ServerId'=>null) );
if ( count($storage_areas) < 4 )
echo implode( ', ', array_map ( $func, $storage_areas ) );
echo ' ' . ZM_PATH_MAP .': '. getDiskPercent(ZM_PATH_MAP).'%';
?></li>

View File

@ -37,7 +37,7 @@ $eventCounts = array(
'filter' => array(
'Query' => array(
'terms' => array(
array( 'attr' => 'DateTime', 'op' => '>=', 'val' => '-1 hour' ),
array( 'attr' => 'StartDateTime', 'op' => '>=', 'val' => '-1 hour' ),
)
)
),

View File

@ -55,7 +55,17 @@ function SetImageSource( monId, time ) {
if ( eMonId[i] == monId && time >= eStartSecs[i] && time <= eEndSecs[i] ) {
var duration = eEndSecs[i]-eStartSecs[i];
var frame = parseInt((time - eStartSecs[i])/(duration)*eventFrames[i])+1;
console.log("SetImageSource: " + time + " duration: " + duration + " frame: " + frame );
var storage = Storage[eStorageId[i]];
if ( storage.ServerId ) {
var server = Servers[storage.ServerId];
if ( server ) {
console.log( server.Hostname + " for event " + eId[i] );
return location.protocol + '//' + server.Hostname + '/index.php?view=image&eid=' + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height;
} else {
console.log("No server found for " + storage.ServerId );
}
}
console.log("No storage found for " + eStorageId[i] );
return "index.php?view=image&eid=" + eId[i] + '&fid='+frame + "&width=" + monitorCanvasObj[monId].width + "&height=" + monitorCanvasObj[monId].height;
}
} // end for
@ -465,7 +475,6 @@ function setSpeed( speed_index ) {
currentSpeed = parseFloat(speeds[speed_index]);
speedIndex = speed_index;
playSecsperInterval = Math.floor( 1000 * currentSpeed * currentDisplayInterval ) / 1000000;
console.log("playSecsPerInterval: " + playSecsperInterval + " = currentspeed:" + currentSpeed + " * " + currentDisplayInterval + " /1000");
showSpeed(speed_index);
if ( timerInterval != currentDisplayInterval || currentSpeed == 0 ) timerFire(); // if the timer isn't firing we need to trigger it to update
}

View File

@ -23,6 +23,7 @@ var imageLoadTimesNeeded=15; // and how many we need
var timeLabelsFractOfRow = 0.9;
var eMonId = [];
var eId = [];
var eStorageId = [];
var eStartSecs = [];
var eEndSecs = [];
var eventFrames = []; // this is going to presume all frames equal durationlength
@ -43,7 +44,6 @@ $index = 0;
$anyAlarms = false;
if ( ! $initialModeIsLive ) {
Warning($eventsSql);
$result = dbQuery( $eventsSql );
if ( ! $result ) {
Fatal('SQL-ERR');
@ -56,6 +56,7 @@ Warning($eventsSql);
if ( $maxTimeSecs < $event['CalcEndTimeSecs'] ) $maxTimeSecs = $event['CalcEndTimeSecs'];
echo "
eMonId[$index]=" . $event['MonitorId'] . ";
eStorageId[$index]=".$event['StorageId'] . ";
eId[$index]=" . $event['Id'] . ";
eStartSecs[$index]=" . $event['StartTimeSecs'] . ";
eEndSecs[$index]=" . $event['CalcEndTimeSecs'] . ";
@ -146,7 +147,17 @@ if ( $mId > 0 ) {
echo "var maxScore=$maxScore;\n"; // used to skip frame load if we find no alarms.
} // end if initialmodeislive
echo "var monitorName = [];\n";
echo "var Storage = []\n";
foreach ( Storage::find_all() as $Storage ) {
echo 'Storage[' . $Storage->Id() . '] = ' . json_encode($Storage). ";\n";
}
echo "var Servers = []\n";
foreach ( Server::find_all() as $Server ) {
echo 'Servers[' . $Server->Id() . '] = ' . json_encode($Server). ";\n";
}
echo "
var monitorName = [];\n";
echo "var monitorLoading = [];\n";
echo "var monitorImageObject = [];\n";
echo "var monitorImageURL = [];\n";

View File

@ -94,7 +94,7 @@ if (isset($_REQUEST['minTime']) && isset($_REQUEST['maxTime']) && count($display
// Note we round up just a bit on the end time as otherwise you get gaps, like 59.78 to 00 in the next second, which can give blank frames when moved through slowly.
$eventsSql = '
SELECT E.Id,E.Name,UNIX_TIMESTAMP(E.StartTime) AS StartTimeSecs,
SELECT E.Id,E.Name,E.StorageId,UNIX_TIMESTAMP(E.StartTime) AS StartTimeSecs,
CASE WHEN E.EndTime IS NULL THEN (SELECT UNIX_TIMESTAMP(DATE_ADD(E.StartTime, Interval max(Delta)+0.5 Second)) FROM Frames F WHERE F.EventId=E.Id)
ELSE UNIX_TIMESTAMP(E.EndTime)
END AS CalcEndTimeSecs, E.Length,

View File

@ -194,7 +194,7 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
</div>
</form>
<?php
} else if ( $tab == "servers" ) { ?>
} else if ( $tab == 'servers' ) { ?>
<form name="serversForm" method="post" action="<?php echo $_SERVER['PHP_SELF'] ?>">
<input type="hidden" name="view" value="<?php echo $view ?>"/>
<input type="hidden" name="tab" value="<?php echo $tab ?>"/>
@ -249,6 +249,7 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
<th class="colPath"><?php echo translate('path') ?></th>
<th class="colType"><?php echo translate('Type') ?></th>
<th class="colScheme"><?php echo translate('StorageScheme') ?></th>
<th class="colServer"><?php echo translate('Server') ?></th>
<th class="colMark"><?php echo translate('Mark') ?></th>
</tr>
</thead>
@ -260,6 +261,9 @@ foreach( array_map( 'basename', glob('skins/'.$current_skin.'/css/*',GLOB_ONLYDI
<td class="colPath"><?php echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Path']), $canEdit ) ?></td>
<td class="colType"><?php echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Type']), $canEdit ) ?></td>
<td class="colScheme"><?php echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($row['Scheme']), $canEdit ) ?></td>
<td class="colServer"><?php
$Server = new Server($row['ServerId']);
echo makePopupLink( '?view=storage&amp;id='.$row['Id'], 'zmStorage', 'storage', validHtmlStr($Server->Name()), $canEdit ) ?></td>
<td class="colMark"><input type="checkbox" name="markIds[]" value="<?php echo $row['Id'] ?>" onclick="configureDeleteButton(this);"<?php if ( !$canEdit ) { ?> disabled="disabled"<?php } ?>/></td>
</tr>
<?php } #end foreach Server ?>

View File

@ -43,6 +43,11 @@ $scheme_options = array(
'Shallow' => translate('Shallow'),
);
$servers = Server::find_all();
$ServersById = array();
foreach ( $servers as $S ) {
$ServersById[$S->Id()] = $S;
}
$focusWindow = true;
xhtmlHeaders(__FILE__, translate('Storage')." - ".$newStorage['Name'] );
@ -67,6 +72,10 @@ xhtmlHeaders(__FILE__, translate('Storage')." - ".$newStorage['Name'] );
<th scope="row"><?php echo translate('Path') ?></th>
<td><input type="text" name="newStorage[Path]" value="<?php echo $newStorage['Path'] ?>"/></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Server') ?></th>
<td><?php echo htmlSelect( 'newStorage[ServerId]', array('','Remote') + $ServersById, $newStorage['ServerId'] ); ?></td>
</tr>
<tr>
<th scope="row"><?php echo translate('Type') ?></th>
<td><?php echo htmlSelect( 'newStorage[Type]', $type_options, $newStorage['Type'] ); ?></td>