3
* Spring Signage Ltd - http://www.springsignage.com
4
* Copyright (C) 2016 Spring Signage Ltd
5
* (DisplayNotifyService.php)
9
namespace Xibo\Service;
10
use Stash\Interfaces\PoolInterface;
11
use Xibo\Entity\Display;
12
use Xibo\Exception\DeadlockException;
13
use Xibo\Factory\DayPartFactory;
14
use Xibo\Factory\ScheduleFactory;
15
use Xibo\Storage\StorageServiceInterface;
16
use Xibo\XMR\CollectNowAction;
19
* Class DisplayNotifyService
20
* @package Xibo\Service
22
class DisplayNotifyService implements DisplayNotifyServiceInterface
24
/** @var ConfigServiceInterface */
27
/** @var LogServiceInterface */
30
/** @var StorageServiceInterface */
33
/** @var PoolInterface */
36
/** @var PlayerActionServiceInterface */
37
private $playerActionService;
39
/** @var DateServiceInterface */
42
/** @var ScheduleFactory */
43
private $scheduleFactory;
45
/** @var DayPartFactory */
46
private $dayPartFactory;
49
private $collectRequired = false;
52
private $displayIds = [];
55
private $displayIdsRequiringActions = [];
58
public function __construct($config, $log, $store, $pool, $playerActionService, $dateService, $scheduleFactory, $dayPartFactory)
60
$this->config = $config;
62
$this->store = $store;
64
$this->playerActionService = $playerActionService;
65
$this->dateService = $dateService;
66
$this->scheduleFactory = $scheduleFactory;
67
$this->dayPartFactory = $dayPartFactory;
71
public function init()
73
$this->collectRequired = false;
78
public function collectNow()
80
$this->collectRequired = true;
85
public function collectLater()
87
$this->collectRequired = false;
92
public function processQueue()
94
if (count($this->displayIds) <= 0)
97
$this->log->debug('Process queue of ' . count($this->displayIds) . ' display notifications');
99
// We want to do 3 things.
100
// 1. Drop the Cache for each displayId
101
// 2. Update the mediaInventoryStatus on each DisplayId to 3 (pending)
102
// 3. Fire a PlayerAction if appropriate - what is appropriate?!
104
// Unique our displayIds
105
$displayIds = array_values(array_unique($this->displayIds, SORT_NUMERIC));
107
// Make a list of them that we can use in the update statement
108
$qmarks = str_repeat('?,', count($displayIds) - 1) . '?';
111
$this->store->updateWithDeadlockLoop('UPDATE `display` SET mediaInventoryStatus = 3 WHERE displayId IN (' . $qmarks . ')', $displayIds);
112
} catch (DeadlockException $deadlockException) {
113
$this->log->error('Failed to update media inventory status: ' . $deadlockException->getMessage());
117
foreach ($displayIds as $displayId) {
118
$this->pool->deleteItem(Display::getCachePrefix() . $displayId);
122
$this->processPlayerActions();
128
private function processPlayerActions()
130
if (count($this->displayIdsRequiringActions) <= 0)
133
$this->log->debug('Process queue of ' . count($this->displayIdsRequiringActions) . ' display actions');
135
$displayIdsRequiringActions = array_values(array_unique($this->displayIdsRequiringActions, SORT_NUMERIC));
136
$qmarks = str_repeat('?,', count($displayIdsRequiringActions) - 1) . '?';
137
$displays = $this->store->select('SELECT displayId, xmrChannel, xmrPubKey FROM `display` WHERE displayId IN (' . $qmarks . ')', $displayIdsRequiringActions);
139
foreach ($displays as $display) {
140
$stdObj = new \stdClass();
141
$stdObj->displayId = $display['displayId'];
142
$stdObj->xmrChannel = $display['xmrChannel'];
143
$stdObj->xmrPubKey = $display['xmrPubKey'];
146
$this->playerActionService->sendAction($stdObj, new CollectNowAction());
147
} catch (\Exception $e) {
148
$this->log->notice('DisplayId ' . $display['displayId'] . ' Save would have triggered Player Action, but the action failed with message: ' . $e->getMessage());
154
public function notifyByDisplayId($displayId)
156
$this->log->debug('Notify by DisplayId ' . $displayId);
158
$this->displayIds[] = $displayId;
160
if ($this->collectRequired)
161
$this->displayIdsRequiringActions[] = $displayId;
165
public function notifyByDisplayGroupId($displayGroupId)
167
$this->log->debug('Notify by DisplayGroupId ' . $displayGroupId);
170
SELECT DISTINCT `lkdisplaydg`.displayId
172
INNER JOIN `lkdisplaydg`
173
ON `lkdisplaydg`.displayGroupID = `lkdgdg`.childId
174
WHERE `lkdgdg`.parentId = :displayGroupId
177
foreach ($this->store->select($sql, ['displayGroupId' => $displayGroupId]) as $row) {
178
$this->displayIds[] = $row['displayId'];
180
$this->log->debug('DisplayGroup[' . $displayGroupId .'] change caused notify on displayId[' . $row['displayId'] . ']');
182
if ($this->collectRequired)
183
$this->displayIdsRequiringActions[] = $row['displayId'];
188
public function notifyByCampaignId($campaignId)
190
$this->log->debug('Notify by CampaignId ' . $campaignId);
193
SELECT DISTINCT display.displayId,
197
schedule.recurrence_type AS recurrenceType,
198
schedule.recurrence_detail AS recurrenceDetail,
199
schedule.recurrence_range AS recurrenceRange,
200
schedule.recurrenceRepeatsOn,
201
schedule.lastRecurrenceWatermark,
204
INNER JOIN `lkscheduledisplaygroup`
205
ON `lkscheduledisplaygroup`.eventId = `schedule`.eventId
207
ON `lkdgdg`.parentId = `lkscheduledisplaygroup`.displayGroupId
208
INNER JOIN `lkdisplaydg`
209
ON lkdisplaydg.DisplayGroupID = `lkdgdg`.childId
211
ON lkdisplaydg.DisplayID = display.displayID
215
WHERE campaign.campaignId = :activeCampaignId
217
SELECT DISTINCT parent.campaignId
218
FROM `lkcampaignlayout` child
219
INNER JOIN `lkcampaignlayout` parent
220
ON parent.layoutId = child.layoutId
221
WHERE child.campaignId = :activeCampaignId
224
ON campaigns.campaignId = `schedule`.campaignId
226
(`schedule`.FromDT < :toDt AND IFNULL(`schedule`.toDt, `schedule`.fromDt) > :fromDt)
227
OR `schedule`.recurrence_range >= :fromDt
229
IFNULL(`schedule`.recurrence_range, 0) = 0 AND IFNULL(`schedule`.recurrence_type, \'\') <> \'\'
233
SELECT DISTINCT display.DisplayID,
237
NULL AS recurrenceType,
238
NULL AS recurrenceDetail,
239
NULL AS recurrenceRange,
240
NULL AS recurrenceRepeatsOn,
241
NULL AS lastRecurrenceWatermark,
244
INNER JOIN `lkcampaignlayout`
245
ON `lkcampaignlayout`.LayoutID = `display`.DefaultLayoutID
246
WHERE `lkcampaignlayout`.CampaignID = :activeCampaignId2
248
SELECT `lkdisplaydg`.displayId,
252
NULL AS recurrenceType,
253
NULL AS recurrenceDetail,
254
NULL AS recurrenceRange,
255
NULL AS recurrenceRepeatsOn,
256
NULL AS lastRecurrenceWatermark,
259
INNER JOIN `lklayoutdisplaygroup`
260
ON `lklayoutdisplaygroup`.displayGroupId = `lkdisplaydg`.displayGroupId
261
INNER JOIN `lkcampaignlayout`
262
ON `lkcampaignlayout`.layoutId = `lklayoutdisplaygroup`.layoutId
263
WHERE `lkcampaignlayout`.campaignId = :assignedCampaignId
266
$currentDate = $this->dateService->parse();
267
$rfLookAhead = $currentDate->copy()->addSeconds($this->config->GetSetting('REQUIRED_FILES_LOOKAHEAD'));
270
'fromDt' => $currentDate->subHour()->format('U'),
271
'toDt' => $rfLookAhead->format('U'),
272
'activeCampaignId' => $campaignId,
273
'activeCampaignId2' => $campaignId,
274
'assignedCampaignId' => $campaignId
277
foreach ($this->store->select($sql, $params) as $row) {
279
// Is this schedule active?
280
if ($row['eventId'] != 0) {
281
$scheduleEvents = $this->scheduleFactory
284
->getEvents($currentDate, $rfLookAhead);
286
if (count($scheduleEvents) <= 0) {
287
$this->log->debug('Skipping eventId ' . $row['eventId'] . ' because it doesnt have any active events in the window');
292
$this->log->debug('Campaign[' . $campaignId .'] change caused notify on displayId[' . $row['displayId'] . ']');
294
$this->displayIds[] = $row['displayId'];
296
if ($this->collectRequired)
297
$this->displayIdsRequiringActions[] = $row['displayId'];
302
public function notifyByDataSetId($dataSetId)
304
$this->log->debug('Notify by DataSetId ' . $dataSetId);
307
SELECT DISTINCT display.displayId,
311
schedule.recurrence_type AS recurrenceType,
312
schedule.recurrence_detail AS recurrenceDetail,
313
schedule.recurrence_range AS recurrenceRange,
314
schedule.recurrenceRepeatsOn,
315
schedule.lastRecurrenceWatermark,
318
INNER JOIN `lkscheduledisplaygroup`
319
ON `lkscheduledisplaygroup`.eventId = `schedule`.eventId
321
ON `lkdgdg`.parentId = `lkscheduledisplaygroup`.displayGroupId
322
INNER JOIN `lkdisplaydg`
323
ON lkdisplaydg.DisplayGroupID = `lkdgdg`.childId
325
ON lkdisplaydg.DisplayID = display.displayID
326
INNER JOIN `lkcampaignlayout`
327
ON `lkcampaignlayout`.campaignId = `schedule`.campaignId
329
ON `region`.layoutId = `lkcampaignlayout`.layoutId
330
INNER JOIN `lkregionplaylist`
331
ON `lkregionplaylist`.regionId = `region`.regionId
333
ON `widget`.playlistId = `lkregionplaylist`.playlistId
334
INNER JOIN `widgetoption`
335
ON `widgetoption`.widgetId = `widget`.widgetId
336
AND `widgetoption`.type = \'attrib\'
337
AND `widgetoption`.option = \'dataSetId\'
338
AND `widgetoption`.value = :activeDataSetId
340
(schedule.FromDT < :toDt AND IFNULL(`schedule`.toDt, `schedule`.fromDt) > :fromDt)
341
OR `schedule`.recurrence_range >= :fromDt
343
IFNULL(`schedule`.recurrence_range, 0) = 0 AND IFNULL(`schedule`.recurrence_type, \'\') <> \'\'
347
SELECT DISTINCT display.displayId,
351
NULL AS recurrenceType,
352
NULL AS recurrenceDetail,
353
NULL AS recurrenceRange,
354
NULL AS recurrenceRepeatsOn,
355
NULL AS lastRecurrenceWatermark,
358
INNER JOIN `lkcampaignlayout`
359
ON `lkcampaignlayout`.LayoutID = `display`.DefaultLayoutID
361
ON `region`.layoutId = `lkcampaignlayout`.layoutId
362
INNER JOIN `lkregionplaylist`
363
ON `lkregionplaylist`.regionId = `region`.regionId
365
ON `widget`.playlistId = `lkregionplaylist`.playlistId
366
INNER JOIN `widgetoption`
367
ON `widgetoption`.widgetId = `widget`.widgetId
368
AND `widgetoption`.type = \'attrib\'
369
AND `widgetoption`.option = \'dataSetId\'
370
AND `widgetoption`.value = :activeDataSetId2
372
SELECT DISTINCT `lkdisplaydg`.displayId,
376
NULL AS recurrenceType,
377
NULL AS recurrenceDetail,
378
NULL AS recurrenceRange,
379
NULL AS recurrenceRepeatsOn,
380
NULL AS lastRecurrenceWatermark,
382
FROM `lklayoutdisplaygroup`
384
ON `lkdgdg`.parentId = `lklayoutdisplaygroup`.displayGroupId
385
INNER JOIN `lkdisplaydg`
386
ON lkdisplaydg.DisplayGroupID = `lkdgdg`.childId
387
INNER JOIN `lkcampaignlayout`
388
ON `lkcampaignlayout`.layoutId = `lklayoutdisplaygroup`.layoutId
390
ON `region`.layoutId = `lkcampaignlayout`.layoutId
391
INNER JOIN `lkregionplaylist`
392
ON `lkregionplaylist`.regionId = `region`.regionId
394
ON `widget`.playlistId = `lkregionplaylist`.playlistId
395
INNER JOIN `widgetoption`
396
ON `widgetoption`.widgetId = `widget`.widgetId
397
AND `widgetoption`.type = \'attrib\'
398
AND `widgetoption`.option = \'dataSetId\'
399
AND `widgetoption`.value = :activeDataSetId3
402
$currentDate = $this->dateService->parse();
403
$rfLookAhead = $currentDate->copy()->addSeconds($this->config->GetSetting('REQUIRED_FILES_LOOKAHEAD'));
406
'fromDt' => $currentDate->subHour()->format('U'),
407
'toDt' => $rfLookAhead->format('U'),
408
'activeDataSetId' => $dataSetId,
409
'activeDataSetId2' => $dataSetId,
410
'activeDataSetId3' => $dataSetId
413
foreach ($this->store->select($sql, $params) as $row) {
415
// Is this schedule active?
416
if ($row['eventId'] != 0) {
417
$scheduleEvents = $this->scheduleFactory
420
->getEvents($currentDate, $rfLookAhead);
422
if (count($scheduleEvents) <= 0) {
423
$this->log->debug('Skipping eventId ' . $row['eventId'] . ' because it doesnt have any active events in the window');
428
$this->log->debug('DataSet[' . $dataSetId .'] change caused notify on displayId[' . $row['displayId'] . ']');
430
$this->displayIds[] = $row['displayId'];
432
if ($this->collectRequired)
433
$this->displayIdsRequiringActions[] = $row['displayId'];
438
public function notifyByPlaylistId($playlistId)
440
$this->log->debug('Notify by PlaylistId ' . $playlistId);
443
SELECT DISTINCT display.displayId,
447
schedule.recurrence_type AS recurrenceType,
448
schedule.recurrence_detail AS recurrenceDetail,
449
schedule.recurrence_range AS recurrenceRange,
450
schedule.recurrenceRepeatsOn,
451
schedule.lastRecurrenceWatermark,
454
INNER JOIN `lkscheduledisplaygroup`
455
ON `lkscheduledisplaygroup`.eventId = `schedule`.eventId
457
ON `lkdgdg`.parentId = `lkscheduledisplaygroup`.displayGroupId
458
INNER JOIN `lkdisplaydg`
459
ON lkdisplaydg.DisplayGroupID = `lkdgdg`.childId
461
ON lkdisplaydg.DisplayID = display.displayID
462
INNER JOIN `lkcampaignlayout`
463
ON `lkcampaignlayout`.campaignId = `schedule`.campaignId
465
ON `lkcampaignlayout`.layoutId = region.layoutId
466
INNER JOIN `lkregionplaylist`
467
ON `lkregionplaylist`.regionId = `region`.regionId
468
WHERE `lkregionplaylist`.playlistId = :playlistId
470
(schedule.FromDT < :toDt AND IFNULL(`schedule`.toDt, `schedule`.fromDt) > :fromDt)
471
OR `schedule`.recurrence_range >= :fromDt
473
IFNULL(`schedule`.recurrence_range, 0) = 0 AND IFNULL(`schedule`.recurrence_type, \'\') <> \'\'
477
SELECT DISTINCT display.DisplayID,
481
NULL AS recurrenceType,
482
NULL AS recurrenceDetail,
483
NULL AS recurrenceRange,
484
NULL AS recurrenceRepeatsOn,
485
NULL AS lastRecurrenceWatermark,
488
INNER JOIN `lkcampaignlayout`
489
ON `lkcampaignlayout`.LayoutID = `display`.DefaultLayoutID
491
ON `lkcampaignlayout`.layoutId = region.layoutId
492
INNER JOIN `lkregionplaylist`
493
ON `lkregionplaylist`.regionId = `region`.regionId
494
WHERE `lkregionplaylist`.playlistId = :playlistId
496
SELECT `lkdisplaydg`.displayId,
500
NULL AS recurrenceType,
501
NULL AS recurrenceDetail,
502
NULL AS recurrenceRange,
503
NULL AS recurrenceRepeatsOn,
504
NULL AS lastRecurrenceWatermark,
507
INNER JOIN `lklayoutdisplaygroup`
508
ON `lklayoutdisplaygroup`.displayGroupId = `lkdisplaydg`.displayGroupId
509
INNER JOIN `lkcampaignlayout`
510
ON `lkcampaignlayout`.layoutId = `lklayoutdisplaygroup`.layoutId
512
ON `lkcampaignlayout`.layoutId = region.layoutId
513
INNER JOIN `lkregionplaylist`
514
ON `lkregionplaylist`.regionId = `region`.regionId
515
WHERE `lkregionplaylist`.playlistId = :playlistId
518
$currentDate = $this->dateService->parse();
519
$rfLookAhead = $currentDate->copy()->addSeconds($this->config->GetSetting('REQUIRED_FILES_LOOKAHEAD'));
522
'fromDt' => $currentDate->subHour()->format('U'),
523
'toDt' => $rfLookAhead->format('U'),
524
'playlistId' => $playlistId
527
foreach ($this->store->select($sql, $params) as $row) {
529
// Is this schedule active?
530
if ($row['eventId'] != 0) {
531
$scheduleEvents = $this->scheduleFactory
534
->getEvents($currentDate, $rfLookAhead);
536
if (count($scheduleEvents) <= 0) {
537
$this->log->debug('Skipping eventId ' . $row['eventId'] . ' because it doesnt have any active events in the window');
542
$this->log->debug('Playlist[' . $playlistId .'] change caused notify on displayId[' . $row['displayId'] . ']');
544
$this->displayIds[] = $row['displayId'];
546
if ($this->collectRequired)
547
$this->displayIdsRequiringActions[] = $row['displayId'];
b'\\ No newline at end of file'