Skip to content

Commit

Permalink
refactor,fix(desktop-notifications-poc): added missing PHPDocs, impro…
Browse files Browse the repository at this point in the history
…ved code quality, fixed formatting
  • Loading branch information
ncosta-ic committed Apr 23, 2024
1 parent 9186c33 commit 5853886
Show file tree
Hide file tree
Showing 17 changed files with 536 additions and 468 deletions.
2 changes: 1 addition & 1 deletion application/clicommands/DaemonCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ class DaemonCommand extends Command
{
public function runAction(): void
{
$daemon = Daemon::get();
Daemon::get();
}
}
24 changes: 17 additions & 7 deletions application/controllers/DaemonController.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@
use ipl\Web\Compat\ViewRenderer;
use Zend_Layout;

final class DaemonController extends CompatController
class DaemonController extends CompatController
{
protected $requiresAuthentication = false;

public function init(): void
{
/**
* override init function and disable Zend rendering as this controller provides no graphical output
/*
* Initialize the controller and disable view renderer and layout as this controller provides no graphical output
*/
/** @var ViewRenderer $viewRenderer */
$viewRenderer = $this->getHelper('viewRenderer');
Expand All @@ -32,11 +32,14 @@ public function scriptAction(): void
$this->httpNotFound("File extension is missing.");
case '.js':
$mime = 'application/javascript';

break;
case '.js.map':
$mime = 'application/json';

break;
}

$root = Icinga::app()
->getModuleManager()
->getModule('notifications')
Expand All @@ -52,6 +55,7 @@ public function scriptAction(): void
if ($this->_getParam('file') === null) {
$this->httpNotFound("No file name submitted");
}

$this->httpNotFound(
"'notifications-"
. $this->_getParam('file')
Expand All @@ -60,7 +64,6 @@ public function scriptAction(): void
);
} else {
$fileStat = stat($filePath);
$eTag = '';
if ($fileStat) {
$eTag = sprintf(
'%x-%x-%x',
Expand All @@ -81,7 +84,14 @@ public function scriptAction(): void
$this->getResponse()
->setHeader('ETag', $eTag)
->setHeader('Content-Type', $mime, true)
->setHeader('Last-Modified', gmdate('D, d M Y H:i:s', $fileStat['mtime']) . ' GMT');
->setHeader(
'Last-Modified',
gmdate(
'D, d M Y H:i:s',
$fileStat['mtime']
)
. ' GMT'
);
$file = file_get_contents($filePath);
if ($file) {
$this->getResponse()->setBody($file);
Expand All @@ -90,8 +100,8 @@ public function scriptAction(): void
} else {
$this->httpNotFound(
"'notifications-"
. $this->_getParam('file')
. $this->_getParam('extension')
. $this->params->get('file')
. $this->params->get('extension')
. " could not be read"
);
}
Expand Down
159 changes: 102 additions & 57 deletions library/Notifications/Daemon/Daemon.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?php /** @noinspection PhpComposerExtensionStubsInspection */
<?php
/** @noinspection PhpComposerExtensionStubsInspection */

namespace Icinga\Module\Notifications\Daemon;

Expand All @@ -8,67 +9,53 @@
use Icinga\Application\Logger;
use Icinga\Module\Notifications\Common\Database;
use Icinga\Module\Notifications\Model\Daemon\BrowserSession;
use Icinga\Module\Notifications\Model\Daemon\Connection;
use Icinga\Module\Notifications\Model\Daemon\Event;
use Icinga\Module\Notifications\Model\Daemon\EventIdentifier;
use Icinga\Module\Notifications\Model\IncidentHistory;
use Icinga\Module\Notifications\Model\ObjectIdTag;
use ipl\Sql\Connection;
use ipl\Sql\Connection as SQLConnection;
use ipl\Stdlib\Filter;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;

use function Clue\React\Block\await;
use function React\Promise\Timer\sleep;

final class Daemon extends EventEmitter
class Daemon extends EventEmitter
{
private const PREFIX = '[daemon] - ';
protected const PREFIX = '[daemon] - ';

/**
* @var Logger $logger
*/
private static $logger;
/** @var Logger $logger */
protected static $logger;

/**
* @var Daemon $instance
*/
/** @var Daemon $instance */
private static $instance;

/**
* @var LoopInterface $loop
*/
private $loop;
/** @var LoopInterface $loop */
protected $loop;

/**
* @var Server $server
*/
private $server;
/** @var Server $server */
protected $server;

/**
* @var Sender $sender
*/
private $sender;
/** @var Sender $sender */
protected $sender;

/**
* @var Connection $database
*/
private $database;
/** @var SQLConnection $database */
protected $database;

/**
* @var bool $cancellationToken
*/
private $cancellationToken;
/** @var bool $cancellationToken */
protected $cancellationToken;

/**
* @var int $initializedAt
*/
private $initializedAt;
/** @var int $initializedAt */
protected $initializedAt;

/** @var int $lastIncidentId */
protected $lastIncidentId;

/**
* @var int $lastIncidentId
* Construct the singleton instance of the Daemon class
*/
private $lastIncidentId;

private function __construct()
{
self::$logger = Logger::getInstance();
Expand All @@ -77,6 +64,11 @@ private function __construct()
$this->load();
}

/**
* Return the singleton instance of the Daemon class
*
* @return Daemon Singleton instance
*/
public static function get(): Daemon
{
if (self::$instance === null) {
Expand All @@ -86,7 +78,12 @@ public static function get(): Daemon
return self::$instance;
}

private function load(): void
/**
* Run the loading logic
*
* @return void
*/
protected function load(): void
{
self::$logger::debug(self::PREFIX . "loading");

Expand All @@ -95,19 +92,28 @@ private function load(): void
$this->server = Server::get($this->loop);
$this->sender = Sender::get($this, $this->server);
$this->database = Database::get();

$this->database->connect();

$this->cancellationToken = false;
$this->initializedAt = time();

$this->run();

self::$logger::debug(self::PREFIX . "loaded");
}

public function unload(): void
/**
* Run the unloading logic
*
* @return void
*/
protected function unload(): void
{
self::$logger::debug(self::PREFIX . "unloading");

$this->cancellationToken = true;

$this->database->disconnect();
$this->server->unload();
$this->sender->unload();
Expand All @@ -122,7 +128,12 @@ public function unload(): void
self::$logger::debug(self::PREFIX . "unloaded");
}

public function reload(): void
/**
* Run the reloading logic
*
* @return void
*/
protected function reload(): void
{
self::$logger::debug(self::PREFIX . "reloading");

Expand All @@ -132,7 +143,14 @@ public function reload(): void
self::$logger::debug(self::PREFIX . "reloaded");
}

private function shutdown(bool $isManualShutdown = false): void
/**
* Unload the class object and exit the script
*
* @param bool $isManualShutdown manual trigger for the shutdown
*
* @return never-return
*/
protected function shutdown(bool $isManualShutdown = false): void
{
self::$logger::info(self::PREFIX . "shutting down" . ($isManualShutdown ? " (manually triggered)" : ""));

Expand All @@ -143,7 +161,14 @@ private function shutdown(bool $isManualShutdown = false): void
exit(0);
}

private function signalHandling(LoopInterface $loop): void
/**
* (Re-)Attach to process exit signals and call the shutdown logic
*
* @param LoopInterface $loop ReactPHP's main loop
*
* @return void
*/
protected function signalHandling(LoopInterface $loop): void
{
$reloadFunc = function () {
$this->reload();
Expand All @@ -165,9 +190,15 @@ private function signalHandling(LoopInterface $loop): void
$loop->addSignal(SIGTERM, $exitFunc);
}

private function housekeeping(): void
/**
* Clean up old sessions in the database
*
* @return void
*/
protected function housekeeping(): void
{
self::$logger::debug(self::PREFIX . "running housekeeping job");

$staleBrowserSessions = BrowserSession::on(Database::get())
->filter(Filter::lessThan('authenticated_at', time() - 86400));
$deletions = 0;
Expand All @@ -186,10 +217,16 @@ private function housekeeping(): void
if ($deletions > 0) {
self::$logger::info(self::PREFIX . "housekeeping cleaned " . $deletions . " stale browser sessions");
}

self::$logger::debug(self::PREFIX . "finished housekeeping job");
}

private function processNotifications(): void
/**
* Process new notifications (if there are any)
*
* @return void
*/
protected function processNotifications(): void
{
$numOfNotifications = 0;

Expand All @@ -216,7 +253,7 @@ private function processNotifications(): void
->filter(Filter::greaterThan('id', $this->lastIncidentId))
->filter(Filter::equal('type', 'notified'))
->orderBy('id', 'ASC');
/** @var array<int, array<\Icinga\Module\Notifications\Model\Daemon\Connection>> $connections */
/** @var array<int, array<Connection>> $connections */
$connections = $this->server->getMatchedConnections();

/** @var IncidentHistory $notification */
Expand All @@ -241,9 +278,11 @@ private function processNotifications(): void
switch ($tag->tag) {
case 'host':
$host = $tag->value;

break;
case 'service':
$service = $tag->value;

break;
}
}
Expand All @@ -260,20 +299,16 @@ private function processNotifications(): void
$notification->contact_id,
(object) [
'incident_id' => $incident->incident_id,
'event_id' => $incident->event_id,
'host' => $host,
'service' => $service,
'time' => $time,
'severity' => $incident->incident->severity
],
// minus one as it's usually expected as an auto-incrementing id, we just want to pass it
// the actual id in this case
intval($notification->id - 1)
'event_id' => $incident->event_id,
'host' => $host,
'service' => $service,
'time' => $time,
'severity' => $incident->incident->severity
]
);

$this->emit(EventIdentifier::ICINGA2_NOTIFICATION, array($event));

// self::$logger::warning(self::PREFIX . @var_export($event, true));
++$numOfNotifications;
}
}
Expand All @@ -286,7 +321,17 @@ private function processNotifications(): void
}
}

private function run(): void
/**
* Run main logic
*
* This method registers the needed Daemon routines on PhpReact's {@link Loop main loop}.
* It adds a cancellable infinite loop, which processes new database entries (notifications) every 3 seconds.
* In addition, a cleanup routine gets registered, which cleans up stale browser sessions each hour if they are
* older than a day.
*
* @return void
*/
protected function run(): void
{
$this->loop->futureTick(function () {
while ($this->cancellationToken === false) {
Expand Down
Loading

0 comments on commit 5853886

Please sign in to comment.