Files
Cloud-CMS/lib/Xmds/Soap6.php
Matt Batchelder 05ce0da296 Initial Upload
2025-12-02 10:32:59 -05:00

234 lines
9.4 KiB
PHP

<?php
/*
* Copyright (C) 2024 Xibo Signage Ltd
*
* Xibo - Digital Signage - https://xibosignage.com
*
* This file is part of Xibo.
*
* Xibo is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* Xibo is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with Xibo. If not, see <http://www.gnu.org/licenses/>.
*/
namespace Xibo\Xmds;
use Carbon\Carbon;
use Xibo\Entity\Bandwidth;
use Xibo\Helper\DateFormatHelper;
use Xibo\Support\Sanitizer\SanitizerInterface;
/**
* Class Soap6
* @package Xibo\Xmds
*/
class Soap6 extends Soap5
{
/**
* Report Player Fault to the CMS
*
* @param string $serverKey
* @param string $hardwareKey
* @param string $fault
*
* @return bool
*/
public function reportFaults(string $serverKey, string $hardwareKey, string $fault): bool
{
$this->logProcessor->setRoute('ReportFault');
//$this->logProcessor->setDisplay(0, 'debug');
$sanitizer = $this->getSanitizer([
'serverKey' => $serverKey,
'hardwareKey' => $hardwareKey
]);
// Sanitize
$serverKey = $sanitizer->getString('serverKey');
$hardwareKey = $sanitizer->getString('hardwareKey');
// Check the serverKey matches
if ($serverKey != $this->getConfig()->getSetting('SERVER_KEY')) {
throw new \SoapFault(
'Sender',
'The Server key you entered does not match with the server key at this address'
);
}
// Auth this request...
if (!$this->authDisplay($hardwareKey)) {
throw new \SoapFault('Receiver', 'This Display is not authorised.');
}
// Now that we authenticated the Display, make sure we are sticking to our bandwidth limit
if (!$this->checkBandwidth($this->display->displayId)) {
throw new \SoapFault('Receiver', 'Bandwidth Limit exceeded');
}
$faultDecoded = json_decode($fault, true);
// check if we should record or update any display events.
$this->manageDisplayAlerts($faultDecoded);
// clear existing records from player_faults table
$this->getStore()->update('DELETE FROM `player_faults` WHERE displayId = :displayId', [
'displayId' => $this->display->displayId
]);
foreach ($faultDecoded as $faultAlert) {
$sanitizedFaultAlert = $this->getSanitizer($faultAlert);
$incidentDt = $sanitizedFaultAlert->getDate(
'date',
['default' => Carbon::now()]
)->format(DateFormatHelper::getSystemFormat());
$expires = $sanitizedFaultAlert->getDate('expires', ['default' => null]);
$code = $sanitizedFaultAlert->getInt('code');
$reason = $sanitizedFaultAlert->getString('reason');
$scheduleId = $sanitizedFaultAlert->getInt('scheduleId');
$layoutId = $sanitizedFaultAlert->getInt('layoutId');
$regionId = $sanitizedFaultAlert->getInt('regionId');
$mediaId = $sanitizedFaultAlert->getInt('mediaId');
$widgetId = $sanitizedFaultAlert->getInt('widgetId');
// Trim the reason if it is too long
if (strlen($reason) >= 255) {
$reason = substr($reason, 0, 255);
}
try {
$dbh = $this->getStore()->getConnection();
$insertSth = $dbh->prepare('
INSERT INTO player_faults (displayId, incidentDt, expires, code, reason, scheduleId, layoutId, regionId, mediaId, widgetId)
VALUES (:displayId, :incidentDt, :expires, :code, :reason, :scheduleId, :layoutId, :regionId, :mediaId, :widgetId)
');
$insertSth->execute([
'displayId' => $this->display->displayId,
'incidentDt' => $incidentDt,
'expires' => $expires,
'code' => $code,
'reason' => $reason,
'scheduleId' => $scheduleId,
'layoutId' => $layoutId,
'regionId' => $regionId,
'mediaId' => $mediaId,
'widgetId' => $widgetId
]);
} catch (\Exception $e) {
$this->getLog()->error('Unable to insert Player Faults records. ' . $e->getMessage());
return false;
}
}
$this->logBandwidth($this->display->displayId, Bandwidth::$REPORTFAULT, strlen($fault));
return true;
}
private function manageDisplayAlerts(array $newPlayerFaults)
{
// check current faults for player
$currentFaults = $this->playerFaultFactory->getByDisplayId($this->display->displayId);
// if we had faults and now we no longer have any to add
// set end date for any existing fault events
// add display event for cleared all faults
if (!empty($currentFaults) && empty($newPlayerFaults)) {
$displayEvent = $this->displayEventFactory->createEmpty();
$displayEvent->eventTypeId = $displayEvent->getEventIdFromString('Player Fault');
$displayEvent->displayId = $this->display->displayId;
// clear any open player fault events for this display
$displayEvent->eventEnd($displayEvent->displayId, $displayEvent->eventTypeId);
// log new event for all faults cleared.
$displayEvent->start = Carbon::now()->format('U');
$displayEvent->end = Carbon::now()->format('U');
$displayEvent->detail = __('All Player faults cleared');
$displayEvent->save();
} else if (empty($currentFaults) && !empty($newPlayerFaults)) {
$codesAdded = [];
// we do not have any faults currently, but new ones will be added
foreach ($newPlayerFaults as $newPlayerFault) {
$sanitizedFaultAlert = $this->getSanitizer($newPlayerFault);
// if we do not have an alert for the specific code yet, add it
if (!in_array($sanitizedFaultAlert->getInt('code'), $codesAdded)) {
$this->addDisplayEvent($sanitizedFaultAlert);
// keep track of added codes, we want a single alert per code
$codesAdded[] = $sanitizedFaultAlert->getInt('code');
}
}
} else if (!empty($newPlayerFaults) && !empty($currentFaults)) {
// we have both existing faults and new faults
$existingFaultsCodes = [];
$newFaultCodes = [];
$codesAdded = [];
// keep track of existing fault codes.
foreach ($currentFaults as $currentFault) {
$existingFaultsCodes[] = $currentFault->code;
}
// go through new faults
foreach ($newPlayerFaults as $newPlayerFault) {
$sanitizedFaultAlert = $this->getSanitizer($newPlayerFault);
$newFaultCodes[] = $sanitizedFaultAlert->getInt('code');
// if it already exists, we do not do anything with alerts
// if it is a new code and was not added already
// add it now
if (!in_array($sanitizedFaultAlert->getInt('code'), $existingFaultsCodes)
&& !in_array($sanitizedFaultAlert->getInt('code'), $codesAdded)
) {
$this->addDisplayEvent($sanitizedFaultAlert);
// keep track of added codes, we want a single alert per code
$codesAdded[] = $sanitizedFaultAlert->getInt('code');
}
}
// go through any existing codes that are no longer reported
// update the end date on all of them.
foreach (array_diff($existingFaultsCodes, $newFaultCodes) as $code) {
$displayEvent = $this->displayEventFactory->createEmpty();
$displayEvent->eventEndByReference(
$this->display->displayId,
$displayEvent->getEventIdFromString('Player Fault'),
$code
);
}
}
}
private function addDisplayEvent(SanitizerInterface $sanitizedFaultAlert)
{
$this->getLog()->debug(
sprintf(
'displayEvent : add new display alert for player fault code %d and displayId %d',
$sanitizedFaultAlert->getInt('code'),
$this->display->displayId
)
);
$displayEvent = $this->displayEventFactory->createEmpty();
$displayEvent->eventTypeId = $displayEvent->getEventIdFromString('Player Fault');
$displayEvent->displayId = $this->display->displayId;
$displayEvent->start = $sanitizedFaultAlert->getDate(
'date',
['default' => Carbon::now()]
)->format('U');
$displayEvent->end = null;
$displayEvent->detail = $sanitizedFaultAlert->getString('reason');
$displayEvent->refId = $sanitizedFaultAlert->getInt('code');
$displayEvent->save();
}
}