Merge branch 'ZoneMinder:master' into master
commit
ec24235cd3
|
@ -1,7 +1,7 @@
|
|||
# ==========================================================================
|
||||
#
|
||||
# ZoneMinder Server Module, $Date$, $Revision$
|
||||
# Copyright (C) 2001-2008 Philip Coombes
|
||||
# ZoneMinder Server Module
|
||||
# Copyright (C) 2023 ZoneMinder Inc
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
|
@ -19,94 +19,52 @@
|
|||
#
|
||||
# ==========================================================================
|
||||
#
|
||||
# This module contains the common definitions and functions used by the rest
|
||||
# of the ZoneMinder scripts
|
||||
#
|
||||
package ZoneMinder::Server;
|
||||
|
||||
use 5.006;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
require Exporter;
|
||||
require ZoneMinder::Base;
|
||||
require ZoneMinder::Config;
|
||||
require ZoneMinder::Logger;
|
||||
require ZoneMinder::Object;
|
||||
|
||||
our @ISA = qw(Exporter ZoneMinder::Base);
|
||||
use parent qw(ZoneMinder::Object);
|
||||
|
||||
# Items to export into callers namespace by default. Note: do not export
|
||||
# names by default without a very good reason. Use EXPORT_OK instead.
|
||||
# Do not simply export all your public functions/methods/constants.
|
||||
|
||||
# This allows declaration use ZoneMinder ':all';
|
||||
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
||||
# will save memory.
|
||||
our %EXPORT_TAGS = (
|
||||
'functions' => [ qw(
|
||||
CpuLoad
|
||||
) ]
|
||||
);
|
||||
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
||||
|
||||
our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
|
||||
|
||||
our @EXPORT = qw();
|
||||
|
||||
our $VERSION = $ZoneMinder::Base::VERSION;
|
||||
|
||||
# ==========================================================================
|
||||
#
|
||||
# General Utility Functions
|
||||
#
|
||||
# ==========================================================================
|
||||
|
||||
use ZoneMinder::Config qw(:all);
|
||||
use ZoneMinder::Logger qw(:all);
|
||||
use ZoneMinder::Database qw(:all);
|
||||
|
||||
use POSIX;
|
||||
|
||||
sub new {
|
||||
my ( $parent, $id, $data ) = @_;
|
||||
|
||||
my $self = {};
|
||||
bless $self, $parent;
|
||||
if ( ( $$self{Id} = $id ) or $data ) {
|
||||
#$log->debug("loading $parent $id") if $debug or DEBUG_ALL;
|
||||
$self->load( $data );
|
||||
}
|
||||
return $self;
|
||||
} # end sub new
|
||||
|
||||
sub load {
|
||||
my ( $self, $data ) = @_;
|
||||
my $type = ref $self;
|
||||
if ( ! $data ) {
|
||||
#$log->debug("Object::load Loading from db $type");
|
||||
$data = $ZoneMinder::Database::dbh->selectrow_hashref( 'SELECT * FROM Servers WHERE Id=?', {}, $$self{Id} );
|
||||
if ( ! $data ) {
|
||||
if ( $ZoneMinder::Database::dbh->errstr ) {
|
||||
Error( "Failure to load Server record for $$self{id}: Reason: " . $ZoneMinder::Database::dbh->errstr );
|
||||
} # end if
|
||||
} # end if
|
||||
} # end if ! $data
|
||||
if ( $data and %$data ) {
|
||||
@$self{keys %$data} = values %$data;
|
||||
} # end if
|
||||
} # end sub load
|
||||
|
||||
sub Name {
|
||||
if ( @_ > 1 ) {
|
||||
$_[0]{Name} = $_[1];
|
||||
}
|
||||
return $_[0]{Name};
|
||||
} # end sub Name
|
||||
|
||||
sub Hostname {
|
||||
if ( @_ > 1 ) {
|
||||
$_[0]{Hostname} = $_[1];
|
||||
}
|
||||
return $_[0]{Hostname};
|
||||
} # end sub Hostname
|
||||
use vars qw/ $table $primary_key %fields $serial @identified_by %defaults $debug/;
|
||||
$debug = 0;
|
||||
$table = 'Servers';
|
||||
@identified_by = ('Id');
|
||||
$serial = $primary_key = 'Id';
|
||||
%fields = map { $_, $_ } qw(
|
||||
Id
|
||||
Name
|
||||
Protocol
|
||||
Hostname
|
||||
Port
|
||||
PathToIndex
|
||||
PathToZMS
|
||||
PathToApi
|
||||
State_Id
|
||||
Status
|
||||
CpuLoad
|
||||
CpuUserPercent
|
||||
CpuNicePercent
|
||||
CpuSystemPercent
|
||||
CpuIdlePercent
|
||||
CpuUsagePercent
|
||||
TotalMem
|
||||
FreeMem
|
||||
TotalSwap
|
||||
FreeSwap
|
||||
zmstats
|
||||
zmaudit
|
||||
zmtrigger
|
||||
zmeventnotification
|
||||
Latitude
|
||||
Longitude
|
||||
);
|
||||
|
||||
sub CpuLoad {
|
||||
my $output = qx(uptime);
|
||||
|
@ -114,16 +72,84 @@ sub CpuLoad {
|
|||
# returned value is 1min, 5min, 15min load
|
||||
|
||||
if (join(', ',@sysloads) =~ /(\d+\.\d+)\s*,\s+(\d+\.\d+)\s*,\s+(\d+\.\d+)\s*$/) {
|
||||
if (@_) {
|
||||
my $self = shift;
|
||||
$$self{CpuLoad} = $sysloads[0];
|
||||
}
|
||||
return @sysloads;
|
||||
}
|
||||
|
||||
return (undef, undef, undef);
|
||||
} # end sub CpuLoad
|
||||
|
||||
sub CpuUsage {
|
||||
if (-e '/proc/stat') {
|
||||
if (!open(STAT, '/proc/stat')) {
|
||||
Error("Enable to open /proc/stat: $!");
|
||||
return;
|
||||
}
|
||||
my ($self, $prev_user, $prev_nice, $prev_sys, $prev_idle, $prev_total);
|
||||
if (@_==1) {
|
||||
$self = shift;
|
||||
($prev_user, $prev_nice, $prev_sys, $prev_idle, $prev_total) = @$self{'prev_user','prev_nice','prev_sys','prev_idle','prev_total'};
|
||||
} elsif (@_>1) {
|
||||
$self = {};
|
||||
($prev_user, $prev_nice, $prev_sys, $prev_idle, $prev_total) = @_;
|
||||
}
|
||||
|
||||
my ($cpu_user, $cpu_nice, $cpu_sys, $cpu_idle);
|
||||
while (<STAT>) {
|
||||
if (/^cpu\s+[0-9]+/) {
|
||||
(undef, $cpu_user, $cpu_nice, $cpu_sys, $cpu_idle) = split /\s+/, $_;
|
||||
last;
|
||||
}
|
||||
}
|
||||
close STAT;
|
||||
|
||||
my $total = $cpu_user + $cpu_nice + $cpu_sys + $cpu_idle;
|
||||
|
||||
my $diff_user = $prev_user ? $cpu_user - $prev_user : $cpu_user;
|
||||
my $diff_nice = $prev_nice ? $cpu_nice - $prev_nice : $cpu_nice;
|
||||
my $diff_sys = $prev_sys ? $cpu_sys - $prev_sys : $cpu_sys;
|
||||
my $diff_idle = $prev_idle ? $cpu_idle - $prev_idle : $cpu_idle;
|
||||
my $diff_total = $prev_total ? $total - $prev_total : $total;
|
||||
|
||||
my $user_percent = 100 * $diff_user / $diff_total;
|
||||
my $nice_percent = 100 * $diff_nice / $diff_total;
|
||||
my $sys_percent = 100 * $diff_sys / $diff_total;
|
||||
my $idle_percent = 100 * $diff_idle / $diff_total;
|
||||
my $usage_percent = 100 * ($diff_total - $diff_idle) / $diff_total;
|
||||
|
||||
$$self{prev_user} = $cpu_user;
|
||||
$$self{prev_nice} = $cpu_nice;
|
||||
$$self{prev_sys} = $cpu_sys;
|
||||
$$self{prev_idle} = $cpu_sys;
|
||||
$$self{prev_total} = $cpu_sys;
|
||||
return ($user_percent, $nice_percent, $sys_percent, $idle_percent, $usage_percent);
|
||||
} else {
|
||||
# Get CPU utilization percentages
|
||||
my $top_output = `top -b -n 1 | grep -i "^%Cpu(s)" | awk '{print \$2, \$4, \$6, \$8}'`;
|
||||
my ($user, $system, $nice, $idle) = split(/ /, $top_output);
|
||||
$user =~ s/[^\d\.]//g;
|
||||
$system =~ s/[^\d\.]//g;
|
||||
$nice =~ s/[^\d\.]//g;
|
||||
$idle =~ s/[^\d\.]//g;
|
||||
if (!$user) {
|
||||
Warning("Failed getting user_utilization from $top_output");
|
||||
$user = 0;
|
||||
}
|
||||
if (!$system) {
|
||||
Warning("Failed getting user_utilization from $top_output");
|
||||
$system = 0;
|
||||
}
|
||||
return ($user, $nice, $system, $idle, $user + $system);
|
||||
}
|
||||
} # end sub CpuUsage
|
||||
|
||||
sub PathToZMS {
|
||||
my $this = shift;
|
||||
$this->{PathToZMS} = shift if @_;
|
||||
if ( $this->Id() and $this->{PathToZMS} ) {
|
||||
if ($this->Id() and $this->{PathToZMS}) {
|
||||
return $this->{PathToZMS};
|
||||
} else {
|
||||
return $ZoneMinder::Config{ZM_PATH_ZMS};
|
||||
|
@ -182,53 +208,13 @@ sub PathToApi {
|
|||
|
||||
1;
|
||||
__END__
|
||||
# Below is stub documentation for your module. You'd better edit it!
|
||||
|
||||
=head1 NAME
|
||||
|
||||
ZoneMinder::Database - Perl extension for blah blah blah
|
||||
ZoneMinder::Server - Perl extension for the ZoneMinder Server Object
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
use ZoneMinder::Server;
|
||||
blah blah blah
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Stub documentation for ZoneMinder, created by h2xs. It looks like the
|
||||
author of the extension was negligent enough to leave the stub
|
||||
unedited.
|
||||
|
||||
Blah blah blah.
|
||||
|
||||
=head2 EXPORT
|
||||
|
||||
None by default.
|
||||
|
||||
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
Mention other useful documentation such as the documentation of
|
||||
related modules or operating system documentation (such as man pages
|
||||
in UNIX), or any relevant external documentation such as RFCs or
|
||||
standards.
|
||||
|
||||
If you have a mailing list set up for your module, mention it here.
|
||||
|
||||
If you have a web site set up for your module, mention it here.
|
||||
|
||||
=head1 AUTHOR
|
||||
|
||||
Philip Coombes, E<lt>philip.coombes@zoneminder.comE<gt>
|
||||
|
||||
=head1 COPYRIGHT AND LICENSE
|
||||
|
||||
Copyright (C) 2001-2008 Philip Coombes
|
||||
|
||||
This library is free software; you can redistribute it and/or modify
|
||||
it under the same terms as Perl itself, either Perl version 5.8.3 or,
|
||||
at your option, any later version of Perl 5 you may have available.
|
||||
|
||||
|
||||
=cut
|
||||
|
|
|
@ -65,6 +65,7 @@ use constant MAX_CONNECT_DELAY => 40;
|
|||
|
||||
@EXTRA_PERL_LIB@
|
||||
use ZoneMinder;
|
||||
use ZoneMinder::Server;
|
||||
use POSIX;
|
||||
use Socket;
|
||||
use IO::Handle;
|
||||
|
@ -155,12 +156,15 @@ socket(CLIENT, PF_UNIX, SOCK_STREAM, 0) or Fatal("Can't open socket: $!");
|
|||
my $saddr = sockaddr_un(SOCK_FILE);
|
||||
my $server_up = connect(CLIENT, $saddr);
|
||||
|
||||
if ( !$server_up ) {
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
if (!$server_up) {
|
||||
my $server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
|
||||
if ($server->Id()) {
|
||||
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
||||
use ZoneMinder::Server qw(CpuLoad);
|
||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?}, undef,
|
||||
'NotRunning', &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
||||
my ($user_percent, $nice_percent, $sys_percent, $idle_percent, $usage_percent) = $server->CpuUsage();
|
||||
if ($_=$server->save({Status=>'NotRunning',
|
||||
TotalMem=>&totalmem, FreeMem=>&freemem, TotalSwap=>&totalswap, FreeSwap=>&freeswap,
|
||||
CpuUserPercent=>$user_percent, CpuNicePercent=>$nice_percent, CpuSysPercent=>$sys_percent, CpuIdlePercent=>$idle_percent, CpuUsagePercent=>$usage_percent,
|
||||
})) {
|
||||
Error('Failed Updating status of Server record to Not Running for Id='.$Config{ZM_SERVER_ID}.': '.$dbh->errstr());
|
||||
}
|
||||
}
|
||||
|
@ -237,7 +241,7 @@ use Socket;
|
|||
use IO::Handle;
|
||||
use Time::HiRes qw(usleep);
|
||||
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
||||
use ZoneMinder::Server qw(CpuLoad);
|
||||
use ZoneMinder::Server;
|
||||
#use Data::Dumper;
|
||||
|
||||
use constant KILL_DELAY => 30; # seconds to wait between sending TERM and sending KILL
|
||||
|
@ -304,9 +308,11 @@ sub run {
|
|||
my $timeout = 1;
|
||||
my $secs_count = 0;
|
||||
|
||||
my $server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
|
||||
|
||||
while ( !$zm_terminate ) {
|
||||
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
if ($server->Id()) {
|
||||
if ( ! ( $secs_count % 60 ) ) {
|
||||
while ( (!$zm_terminate) and !($dbh and $dbh->ping()) ) {
|
||||
Warning("Not connected to db ($dbh)".($dbh?' ping('.$dbh->ping().')':''). ($DBI::errstr?" errstr($DBI::errstr)":'').' Reconnecting');
|
||||
|
@ -315,11 +321,13 @@ sub run {
|
|||
}
|
||||
last if $zm_terminate;
|
||||
|
||||
my @cpuload = CpuLoad();
|
||||
Debug("Updating Server record @cpuload");
|
||||
if ( ! defined $dbh->do('UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?', undef,
|
||||
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
||||
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID} :".$dbh->errstr());
|
||||
my @cpuload = ZoneMinder::Server::CpuLoad();
|
||||
my ($user_percent, $nice_percent, $sys_percent, $idle_percent, $usage_percent) = $server->CpuUsage();
|
||||
if ($_=$server->save({Status=>'Running',
|
||||
TotalMem=>&totalmem, FreeMem=>&freemem, TotalSwap=>&totalswap, FreeSwap=>&freeswap, CpuLoad=>$cpuload[0],
|
||||
CpuUserPercent=>$user_percent, CpuNicePercent=>$nice_percent, CpuSysPercent=>$sys_percent, CpuIdlePercent=>$idle_percent, CpuUsagePercent=>$usage_percent
|
||||
})) {
|
||||
Error('Failed Updating status of Server record to Not Running for Id='.$Config{ZM_SERVER_ID}.': '.$dbh->errstr());
|
||||
}
|
||||
}
|
||||
$secs_count += 1;
|
||||
|
@ -384,14 +392,12 @@ sub run {
|
|||
reaper() if %pids_to_reap;
|
||||
} # end while
|
||||
|
||||
dPrint(ZoneMinder::Logger::INFO, 'Server exiting at '
|
||||
.strftime('%y/%m/%d %H:%M:%S', localtime())
|
||||
."\n"
|
||||
);
|
||||
if ( $Config{ZM_SERVER_ID} ) {
|
||||
dPrint(ZoneMinder::Logger::INFO, 'Server exiting at '.strftime('%y/%m/%d %H:%M:%S', localtime())."\n");
|
||||
if ($Config{ZM_SERVER_ID}) {
|
||||
$dbh = zmDbConnect() if ! ($dbh and $dbh->ping());
|
||||
if ( ! defined $dbh->do(q{UPDATE Servers SET Status='NotRunning' WHERE Id=?}, undef, $Config{ZM_SERVER_ID}) ) {
|
||||
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID}".$dbh->errstr());
|
||||
my $server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
|
||||
if ($_=$server->save({Status=>'NotRunning'})) {
|
||||
Error('Failed Updating status of Server record to Not Running for Id='.$Config{ZM_SERVER_ID}.': '.$dbh->errstr());
|
||||
}
|
||||
}
|
||||
shutdownAll();
|
||||
|
|
|
@ -21,7 +21,7 @@ use constant START_DELAY => 30; # To give everything else time to start
|
|||
use ZoneMinder;
|
||||
use DBI;
|
||||
use Sys::MemInfo qw(totalmem freemem totalswap freeswap);
|
||||
use ZoneMinder::Server qw(CpuLoad);
|
||||
use ZoneMinder::Server;
|
||||
|
||||
$| = 1;
|
||||
|
||||
|
@ -43,6 +43,7 @@ Info('Stats Daemon starting in '.START_DELAY.' seconds');
|
|||
sleep(START_DELAY);
|
||||
|
||||
my $dbh = zmDbConnect();
|
||||
my $server = new ZoneMinder::Server($Config{ZM_SERVER_ID});
|
||||
|
||||
while (!$zm_terminate) {
|
||||
while ( ! ( $dbh and $dbh->ping() ) ) {
|
||||
|
@ -53,34 +54,18 @@ while (!$zm_terminate) {
|
|||
}
|
||||
}
|
||||
|
||||
my @cpuload = CpuLoad();
|
||||
|
||||
if ( $Config{ZM_SERVER_ID} and ! defined $dbh->do('UPDATE Servers SET Status=?,CpuLoad=?,TotalMem=?,FreeMem=?,TotalSwap=?,FreeSwap=? WHERE Id=?', undef,
|
||||
'Running', $cpuload[0], &totalmem, &freemem, &totalswap, &freeswap, $Config{ZM_SERVER_ID} ) ) {
|
||||
Error("Failed Updating status of Server record for Id=$Config{ZM_SERVER_ID} :".$dbh->errstr());
|
||||
}
|
||||
|
||||
# Get CPU utilization percentages
|
||||
my $top_output = `top -b -n 1 | grep -i "^%Cpu(s)" | awk '{print \$2, \$4}'`;
|
||||
my ($user_utilization, $system_utilization) = split(/ /, $top_output);
|
||||
$user_utilization =~ s/[^\d\.]//g;
|
||||
$system_utilization =~ s/[^\d\.]//g;
|
||||
if (!$user_utilization) {
|
||||
Warning("Failed getting user_utilization from $top_output");
|
||||
$user_utilization = 0;
|
||||
}
|
||||
if (!$system_utilization) {
|
||||
Warning("Failed getting user_utilization from $top_output");
|
||||
$system_utilization = 0;
|
||||
}
|
||||
my @cpuload = $server->CpuLoad();
|
||||
|
||||
my ($user_percent, $nice_percent, $sys_percent, $idle_percent, $usage_percent) = $server->CpuUsage();
|
||||
zmDbDo('INSERT INTO Server_Stats (ServerId, TimeStamp, CpuLoad, CpuUserPercent, CpuSystemPercent, TotalMem, FreeMem, TotalSwap, FreeSwap) VALUES (?,NOW(),?,?,?,?,?,?,?)',
|
||||
$Config{ZM_SERVER_ID},
|
||||
$cpuload[0], $user_utilization, $system_utilization,
|
||||
$cpuload[0], $user_percent, $sys_percent,
|
||||
&totalmem, &freemem, &totalswap, &freeswap);
|
||||
|
||||
my $rows = zmDbDo('DELETE FROM `Server_Stats` WHERE `TimeStamp` < now() - interval 1 DAY LIMIT 100');
|
||||
Debug("Deleted $rows Server Stats table entries by time");
|
||||
{
|
||||
my $rows = zmDbDo('DELETE FROM `Server_Stats` WHERE `TimeStamp` < now() - interval 1 DAY LIMIT 100');
|
||||
Debug("Deleted $rows Server Stats table entries by time");
|
||||
}
|
||||
|
||||
# Clear out statuses for Monitors that have been set to None but for some reason didn't update the db
|
||||
zmDbDo('DELETE FROM Monitor_Status WHERE MonitorId IN (SELECT Id FROM Monitors WHERE Capturing=\'None\')');
|
||||
|
@ -114,18 +99,20 @@ while (!$zm_terminate) {
|
|||
}
|
||||
my $rows;
|
||||
do {
|
||||
$rows = zmDbDo('DELETE FROM `Logs` WHERE `TimeKey` < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 100');
|
||||
$rows = zmDbDo('DELETE low_priority FROM `Logs` WHERE `TimeKey` < unix_timestamp(now() - interval '.$Config{ZM_LOG_DATABASE_LIMIT}.') LIMIT 100');
|
||||
Debug("Deleted $rows log table entries by time") if $rows;
|
||||
} while ($rows and ($rows == 100) and !$zm_terminate);
|
||||
}
|
||||
} # end if ZM_LOG_DATABASE_LIMIT
|
||||
|
||||
my $rows;
|
||||
do {
|
||||
# Delete any sessions that are more than a week old. Limiting to 100 because mysql sucks
|
||||
$rows = zmDbDo('DELETE FROM Sessions WHERE access < ? LIMIT 100', time - $Config{ZM_COOKIE_LIFETIME});
|
||||
Debug("Deleted $rows sessions") if $rows;
|
||||
} while ($rows and ($rows == 100) and !$zm_terminate);
|
||||
{
|
||||
my $rows;
|
||||
do {
|
||||
# Delete any sessions that are more than a week old. Limiting to 100 because mysql sucks
|
||||
$rows = zmDbDo('DELETE FROM Sessions WHERE access < ? LIMIT 100', time - $Config{ZM_COOKIE_LIFETIME});
|
||||
Debug("Deleted $rows sessions") if $rows;
|
||||
} while ($rows and ($rows == 100) and !$zm_terminate);
|
||||
}
|
||||
|
||||
sleep($Config{ZM_STATS_UPDATE_INTERVAL});
|
||||
} # end while (!$zm_terminate)
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "zm_logger.h"
|
||||
#include "zm_signal.h"
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
|
||||
MYSQL dbconn;
|
||||
std::mutex db_mutex;
|
||||
|
@ -32,12 +33,12 @@ bool zmDbConnected = false;
|
|||
bool zmDbConnect() {
|
||||
// For some reason having these lines causes memory corruption and crashing on newer debian/ubuntu
|
||||
// But they really need to be here in order to prevent a double open of mysql
|
||||
if ( zmDbConnected ) {
|
||||
if (zmDbConnected) {
|
||||
//Warning("Calling zmDbConnect when already connected");
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( !mysql_init(&dbconn) ) {
|
||||
if (!mysql_init(&dbconn)) {
|
||||
Error("Can't initialise database connection: %s", mysql_error(&dbconn));
|
||||
return false;
|
||||
}
|
||||
|
@ -94,7 +95,7 @@ bool zmDbConnect() {
|
|||
mysql_close(&dbconn);
|
||||
return false;
|
||||
}
|
||||
if ( mysql_query(&dbconn, "SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED") ) {
|
||||
if (mysql_query(&dbconn, "SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED")) {
|
||||
Error("Can't set isolation level: %s", mysql_error(&dbconn));
|
||||
}
|
||||
mysql_set_character_set(&dbconn, "utf8");
|
||||
|
@ -103,6 +104,20 @@ bool zmDbConnect() {
|
|||
return zmDbConnected;
|
||||
}
|
||||
|
||||
/* Calls to zmDbReconnect must have the lock. */
|
||||
bool zmDbReconnect() {
|
||||
if (zmDbConnected) {
|
||||
mysql_close(&dbconn);
|
||||
zmDbConnected = false;
|
||||
}
|
||||
if (zmDbConnect()) {
|
||||
Debug(1, "Reconnected to db...");
|
||||
} else {
|
||||
Debug(1, "Failed to reconnect to db");
|
||||
}
|
||||
return zmDbConnected;
|
||||
}
|
||||
|
||||
void zmDbClose() {
|
||||
std::lock_guard<std::mutex> lck(db_mutex);
|
||||
if (zmDbConnected) {
|
||||
|
@ -126,14 +141,8 @@ MYSQL_RES *zmDbFetch(const std::string &query) {
|
|||
|
||||
if (rc) {
|
||||
Debug(1, "Can't run query: %s rc:%d, reason:%s", query.c_str(), rc, mysql_error(&dbconn));
|
||||
if (mysql_ping(&dbconn)) {
|
||||
zmDbConnected = false;
|
||||
if (zmDbConnect()) {
|
||||
Debug(1, "Reconnected to db...");
|
||||
rc = mysql_query(&dbconn, query.c_str());
|
||||
} else {
|
||||
Debug(1, "Faile to reconnect to db");
|
||||
}
|
||||
if (mysql_ping(&dbconn) and zmDbReconnect()) {
|
||||
rc = mysql_query(&dbconn, query.c_str());
|
||||
}
|
||||
}
|
||||
if (rc) {
|
||||
|
@ -177,6 +186,11 @@ MYSQL_RES *zmDbRow::fetch(const std::string &query) {
|
|||
return result_set;
|
||||
}
|
||||
|
||||
/* performs SQL queries. Will repeat if error is LOCK_WAIT_TIMEOUT
|
||||
* We assume that in general our SQL is properly formed, so errors will
|
||||
* be due to external factors.
|
||||
*/
|
||||
|
||||
int zmDbDo(const std::string &query) {
|
||||
std::lock_guard<std::mutex> lck(db_mutex);
|
||||
if (!zmDbConnected and !zmDbConnect())
|
||||
|
@ -184,40 +198,35 @@ int zmDbDo(const std::string &query) {
|
|||
int rc;
|
||||
while ((rc = mysql_query(&dbconn, query.c_str())) and !zm_terminate) {
|
||||
if (mysql_ping(&dbconn)) {
|
||||
zmDbConnected = false;
|
||||
zmDbConnect();
|
||||
}
|
||||
if (zmDbConnected) {
|
||||
Logger *logger = Logger::fetch();
|
||||
Logger::Level oldLevel = logger->databaseLevel();
|
||||
logger->databaseLevel(Logger::NOLOG);
|
||||
// Was a connection error
|
||||
if (!zmDbReconnect()) {
|
||||
// If we failed. Sleeping 1 sec may be way too much.
|
||||
sleep(1);
|
||||
}
|
||||
} else {
|
||||
// Not a connection error
|
||||
Error("Can't run query %s: %s", query.c_str(), mysql_error(&dbconn));
|
||||
logger->databaseLevel(oldLevel);
|
||||
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) ) {
|
||||
if (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) {
|
||||
return rc;
|
||||
}
|
||||
} // end if connected
|
||||
} // end if !connected
|
||||
}
|
||||
Logger *logger = Logger::fetch();
|
||||
Logger::Level oldLevel = logger->databaseLevel();
|
||||
logger->databaseLevel(Logger::NOLOG);
|
||||
|
||||
Debug(1, "Success running sql query %s, thread_id: %lu", query.c_str(), db_thread_id);
|
||||
logger->databaseLevel(oldLevel);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int zmDbDoInsert(const std::string &query) {
|
||||
std::lock_guard<std::mutex> lck(db_mutex);
|
||||
if (!zmDbConnected and !zmDbConnect())
|
||||
return 0;
|
||||
int rc;
|
||||
while ( (rc = mysql_query(&dbconn, query.c_str())) and !zm_terminate) {
|
||||
while ((rc = mysql_query(&dbconn, query.c_str())) and !zm_terminate) {
|
||||
if (mysql_ping(&dbconn)) {
|
||||
zmDbConnected = false;
|
||||
zmDbConnect();
|
||||
}
|
||||
if (zmDbConnected) {
|
||||
if (!zmDbReconnect()) sleep(1);
|
||||
} else {
|
||||
Error("Can't run query %s: %s", query.c_str(), mysql_error(&dbconn));
|
||||
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) )
|
||||
if ((mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -228,13 +237,13 @@ int zmDbDoInsert(const std::string &query) {
|
|||
|
||||
int zmDbDoUpdate(const std::string &query) {
|
||||
std::lock_guard<std::mutex> lck(db_mutex);
|
||||
if (!zmDbConnected and !zmDbConnect())
|
||||
return 0;
|
||||
int rc;
|
||||
while ( (rc = mysql_query(&dbconn, query.c_str())) and !zm_terminate) {
|
||||
if (mysql_ping(&dbconn)) {
|
||||
zmDbConnected = false;
|
||||
zmDbConnect();
|
||||
}
|
||||
if (zmDbConnected) {
|
||||
if (!zmDbReconnect()) sleep(1);
|
||||
} else {
|
||||
Error("Can't run query %s: %s", query.c_str(), mysql_error(&dbconn));
|
||||
if ( (mysql_errno(&dbconn) != ER_LOCK_WAIT_TIMEOUT) )
|
||||
return -rc;
|
||||
|
|
|
@ -389,49 +389,51 @@ int zm_receive_packet(AVCodecContext *context, AVPacket &packet) {
|
|||
} // end int zm_receive_packet(AVCodecContext *context, AVPacket &packet)
|
||||
|
||||
int zm_send_packet_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet) {
|
||||
int ret;
|
||||
if ((ret = avcodec_send_packet(context, &packet)) < 0) {
|
||||
Error("Unable to send packet %s, continuing",
|
||||
av_make_error_string(ret).c_str());
|
||||
return ret;
|
||||
int pkt_ret, frm_ret;
|
||||
|
||||
pkt_ret = avcodec_send_packet(context, &packet);
|
||||
frm_ret = avcodec_receive_frame(context, frame);
|
||||
|
||||
if (pkt_ret == 0 && frm_ret == 0) {
|
||||
// In this api the packet is always consumed, so return packet.bytes
|
||||
return packet.size;
|
||||
} else if (pkt_ret != 0 && pkt_ret != AVERROR(EAGAIN)) {
|
||||
Error("Could not send packet (error %d = %s)", pkt_ret,
|
||||
av_make_error_string(pkt_ret).c_str());
|
||||
return pkt_ret;
|
||||
} else if (frm_ret != 0 && frm_ret != AVERROR(EAGAIN)) {
|
||||
Error("Could not receive frame (error %d = %s)", frm_ret,
|
||||
av_make_error_string(frm_ret).c_str());
|
||||
return frm_ret;
|
||||
}
|
||||
|
||||
if ((ret = avcodec_receive_frame(context, frame)) < 0) {
|
||||
if (AVERROR(EAGAIN) == ret) {
|
||||
// The codec may need more samples than it has, perfectly valid
|
||||
Debug(2, "Codec not ready to give us a frame");
|
||||
} else {
|
||||
Error("Could not receive frame (error %d = '%s')", ret,
|
||||
av_make_error_string(ret).c_str());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
// In this api the packet is always consumed, so return packet.bytes
|
||||
return packet.size;
|
||||
return 0;
|
||||
} // end int zm_send_packet_receive_frame(AVCodecContext *context, AVFrame *frame, AVPacket &packet)
|
||||
|
||||
/* Returns < 0 on error, 0 if codec not ready, 1 on success
|
||||
*/
|
||||
int zm_send_frame_receive_packet(AVCodecContext *ctx, AVFrame *frame, AVPacket &packet) {
|
||||
int ret;
|
||||
if (((ret = avcodec_send_frame(ctx, frame)) < 0) and frame) {
|
||||
Error("Could not send frame (error '%s')",
|
||||
av_make_error_string(ret).c_str());
|
||||
return ret;
|
||||
}
|
||||
int frm_ret, pkt_ret;
|
||||
|
||||
if ((ret = avcodec_receive_packet(ctx, &packet)) < 0) {
|
||||
if (AVERROR(EAGAIN) == ret) {
|
||||
frm_ret = avcodec_send_frame(ctx, frame);
|
||||
pkt_ret = avcodec_receive_packet(ctx, &packet);
|
||||
|
||||
if (frm_ret != 0 && frame) {
|
||||
Error("Could not send frame (error '%s')",
|
||||
av_make_error_string(frm_ret).c_str());
|
||||
return frm_ret;
|
||||
} else if (pkt_ret != 0) {
|
||||
if (pkt_ret == AVERROR(EAGAIN)) {
|
||||
// The codec may need more samples than it has, perfectly valid
|
||||
Debug(2, "Codec not ready to give us a packet");
|
||||
return 0;
|
||||
} else if (frame) {
|
||||
// May get EOF if frame is NULL because it signals flushing
|
||||
Error("Could not receive packet (error %d = '%s')", ret,
|
||||
av_make_error_string(ret).c_str());
|
||||
Error("Could not receive packet (error %d = '%s')", pkt_ret,
|
||||
av_make_error_string(pkt_ret).c_str());
|
||||
}
|
||||
zm_av_packet_unref(&packet);
|
||||
return ret;
|
||||
return pkt_ret;
|
||||
}
|
||||
return 1;
|
||||
} // end int zm_send_frame_receive_packet
|
||||
|
|
|
@ -13,14 +13,18 @@ class Server extends ZM_Object {
|
|||
public $PathToIndex = '';
|
||||
public $PathToZMS = ZM_PATH_ZMS;
|
||||
public $PathToApi = ZM_PATH_API;
|
||||
public $State_Id = 0;
|
||||
public $State_Id = -1;
|
||||
public $Status = 'Unknown';
|
||||
public $CpuLoad;
|
||||
public $CpuUsagePercent;
|
||||
public $TotalMem;
|
||||
public $FreeMem;
|
||||
public $TotalSwap;
|
||||
public $FreeSwap;
|
||||
public $CpuLoad = -1;
|
||||
public $CpuUserPercent = -1;
|
||||
public $CpuNicePercent = -1;
|
||||
public $CpuSystemPercent = -1;
|
||||
public $CpuIdlePercent = -1;
|
||||
public $CpuUsagePercent = -1;
|
||||
public $TotalMem = -1;
|
||||
public $FreeMem = -1;
|
||||
public $TotalSwap = -1;
|
||||
public $FreeSwap = -1;
|
||||
public $Latitude;
|
||||
public $Longitude;
|
||||
|
||||
|
|
|
@ -272,6 +272,7 @@ function getNormalNavBarHTML($running, $user, $bandwidth_options, $view, $skin)
|
|||
<ul class="navbar-nav list-inline justify-content-center">
|
||||
<?php
|
||||
echo getSysLoadHTML();
|
||||
echo getCpuUsageHTML();
|
||||
echo getDbConHTML();
|
||||
echo getStorageHTML();
|
||||
echo getRamHTML();
|
||||
|
@ -323,6 +324,7 @@ function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $ski
|
|||
<ul class="nav navbar-nav list-group">
|
||||
<?php
|
||||
echo getSysLoadHTML();
|
||||
echo getCpuUsageHTML();
|
||||
echo getDbConHTML();
|
||||
echo getStorageHTML();
|
||||
echo getRamHTML();
|
||||
|
@ -383,6 +385,20 @@ function getCollapsedNavBarHTML($running, $user, $bandwidth_options, $view, $ski
|
|||
<?php
|
||||
} // End function getCollapsedNavBarHTML
|
||||
|
||||
// Returns the html representing the current cpu Usage Percent
|
||||
function getCpuUsageHTML() {
|
||||
$result = '';
|
||||
if ( !canView('System') ) return $result;
|
||||
|
||||
$result .= '<li id="getCpuUsagesHTML" class="CpuUsage nav-item mx-2">'.PHP_EOL;
|
||||
global $thisServer;
|
||||
|
||||
$result .= ' '.translate('Cpu').': '.number_format($thisServer->CpuUsagePercent(), 1, '.', '').'%'.PHP_EOL;
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
// Returns the html representing the current unix style system load
|
||||
function getSysLoadHTML() {
|
||||
$result = '';
|
||||
|
@ -390,7 +406,8 @@ function getSysLoadHTML() {
|
|||
|
||||
$result .= '<li id="getSysLoadHTML" class="Load nav-item mx-2">'.PHP_EOL;
|
||||
$result .= '<i class="material-icons md-18">trending_up</i>'.PHP_EOL;
|
||||
$result .= ' '.translate('Load').': '.number_format(getLoad(), 2, '.', '').PHP_EOL;
|
||||
global $thisServer;
|
||||
$result .= ' '.translate('Load').': '.number_format($thisServer->CpuLoad(), 2, '.', '').PHP_EOL;
|
||||
$result .= '</li>'.PHP_EOL;
|
||||
|
||||
return $result;
|
||||
|
|
|
@ -942,6 +942,10 @@ function watchFullscreen() {
|
|||
}
|
||||
}
|
||||
|
||||
function watchAllEvents() {
|
||||
window.location.replace(document.getElementById('allEventsBtn').getAttribute('data-url'));
|
||||
}
|
||||
|
||||
var intervalId;
|
||||
var secondsToCycle = 0;
|
||||
|
||||
|
|
|
@ -372,6 +372,8 @@ if ($streamMode == 'jpeg') {
|
|||
<button type="button" id="fullscreenBtn" title="<?php echo translate('Fullscreen') ?>" class="avail" data-on-click="watchFullscreen">
|
||||
<i class="material-icons md-18">fullscreen</i>
|
||||
</button>
|
||||
<button type="button" id="allEventsBtn" title="<?php echo translate('All Events') ?>" class="avail" data-on-click="watchAllEvents" data-url="?view=events&page=1&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Battr%5D=Monitor&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Bop%5D=%3D&filter%5BQuery%5D%5Bterms%5D%5B0%5D%5Bval%5D=<?php echo $monitor->Id()?>&filter%5BQuery%5D%5Bsort_asc%5D=1&filter%5BQuery%5D%5Bsort_field%5D=StartDateTime&filter%5BQuery%5D%5Bskip_locked%5D=&filter%5BQuery%5D%5Blimit%5D=0"><?php echo translate('All Events') ?>
|
||||
</button>
|
||||
<?php
|
||||
} // end if streamMode==jpeg
|
||||
?>
|
||||
|
|
Loading…
Reference in New Issue