196 lines
5.8 KiB
PHP
196 lines
5.8 KiB
PHP
<?php
|
|
/*
|
|
* Copyright (C) 2025 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\Service;
|
|
|
|
use GuzzleHttp\Client;
|
|
use GuzzleHttp\Exception\GuzzleException;
|
|
use Xibo\Entity\Display;
|
|
use Xibo\Support\Exception\ConfigurationException;
|
|
use Xibo\Support\Exception\InvalidArgumentException;
|
|
use Xibo\XMR\PlayerAction;
|
|
use Xibo\XMR\PlayerActionException;
|
|
|
|
/**
|
|
* Class PlayerActionService
|
|
* @package Xibo\Service
|
|
*/
|
|
class PlayerActionService implements PlayerActionServiceInterface
|
|
{
|
|
private ?string $xmrAddress;
|
|
|
|
/** @var PlayerAction[] */
|
|
private array $actions = [];
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public function __construct(
|
|
private readonly ConfigServiceInterface $config,
|
|
private readonly LogServiceInterface $log,
|
|
private readonly bool $triggerPlayerActions
|
|
) {
|
|
$this->xmrAddress = null;
|
|
}
|
|
|
|
/**
|
|
* Get Config
|
|
* @return ConfigServiceInterface
|
|
*/
|
|
private function getConfig(): ConfigServiceInterface
|
|
{
|
|
return $this->config;
|
|
}
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public function sendAction($displays, $action): void
|
|
{
|
|
if (!$this->triggerPlayerActions) {
|
|
return;
|
|
}
|
|
|
|
// XMR network address
|
|
if ($this->xmrAddress == null) {
|
|
$this->xmrAddress = $this->getConfig()->getSetting('XMR_ADDRESS');
|
|
}
|
|
|
|
if (empty($this->xmrAddress)) {
|
|
throw new InvalidArgumentException(__('XMR address is not set'), 'xmrAddress');
|
|
}
|
|
|
|
if (!is_array($displays)) {
|
|
$displays = [$displays];
|
|
}
|
|
|
|
// Send a message to all displays
|
|
foreach ($displays as $display) {
|
|
/* @var Display $display */
|
|
$isEncrypt = false;
|
|
|
|
if ($display->xmrChannel == '') {
|
|
throw new InvalidArgumentException(
|
|
sprintf(
|
|
__('%s is not configured or ready to receive push commands over XMR. Please contact your administrator.'),//phpcs:ignore
|
|
$display->display
|
|
),
|
|
'xmrChannel'
|
|
);
|
|
}
|
|
|
|
// If we are using the old ZMQ XMR service, we also need to encrypt the message
|
|
if (!$display->isWebSocketXmrSupported()) {
|
|
// We also need a xmrPubKey
|
|
$isEncrypt = true;
|
|
|
|
if ($display->xmrPubKey == '') {
|
|
throw new InvalidArgumentException(
|
|
sprintf(
|
|
__('%s is not configured or ready to receive push commands over XMR. Please contact your administrator.'),//phpcs:ignore
|
|
$display->display
|
|
),
|
|
'xmrPubKey'
|
|
);
|
|
}
|
|
}
|
|
|
|
// Do not send anything if XMR is disabled.
|
|
if (($isEncrypt && $this->getConfig()->getSetting('XMR_WS_ADDRESS') === 'DISABLED')
|
|
|| (!$isEncrypt && $this->getConfig()->getSetting('XMR_PUB_ADDRESS') === 'DISABLED')
|
|
) {
|
|
continue;
|
|
}
|
|
|
|
$displayAction = clone $action;
|
|
|
|
try {
|
|
$displayAction->setIdentity($display->xmrChannel, $isEncrypt, $display->xmrPubKey ?? null);
|
|
} catch (\Exception $exception) {
|
|
throw new InvalidArgumentException(
|
|
sprintf(
|
|
__('%s Invalid XMR registration'),
|
|
$display->display
|
|
),
|
|
'xmrPubKey'
|
|
);
|
|
}
|
|
|
|
// Add to collection
|
|
$this->actions[] = $displayAction;
|
|
}
|
|
}
|
|
|
|
/** @inheritDoc */
|
|
public function getQueue(): array
|
|
{
|
|
return $this->actions;
|
|
}
|
|
|
|
/**
|
|
* @inheritdoc
|
|
*/
|
|
public function processQueue(): void
|
|
{
|
|
if (count($this->actions) > 0) {
|
|
$this->log->debug('Player Action Service is looking to send %d actions', count($this->actions));
|
|
} else {
|
|
return;
|
|
}
|
|
|
|
// XMR network address
|
|
if ($this->xmrAddress == null) {
|
|
$this->xmrAddress = $this->getConfig()->getSetting('XMR_ADDRESS');
|
|
}
|
|
|
|
$client = new Client($this->config->getGuzzleProxy([
|
|
'base_uri' => $this->getConfig()->getSetting('XMR_ADDRESS'),
|
|
]));
|
|
|
|
$failures = 0;
|
|
|
|
// TODO: could I send them all in one request instead?
|
|
foreach ($this->actions as $action) {
|
|
/** @var PlayerAction $action */
|
|
try {
|
|
// Send each action
|
|
$client->post('/', [
|
|
'json' => $action->finaliseMessage(),
|
|
]);
|
|
} catch (GuzzleException | PlayerActionException $e) {
|
|
$this->log->error('Player action connection failed. E = ' . $e->getMessage());
|
|
$failures++;
|
|
}
|
|
}
|
|
|
|
if ($failures > 0) {
|
|
throw new ConfigurationException(
|
|
sprintf(
|
|
__('%d of %d player actions failed'),
|
|
$failures,
|
|
count($this->actions)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
} |