Completed
Push — master ( 132c41...627059 )
by Sam
02:29
created

StatusManager::onMainLoopStarted()   B

Complexity

Conditions 2
Paths 2

Size

Total Lines 26
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 26
rs 8.8571
cc 2
eloc 12
nc 2
nop 0
1
<?php
2
3
namespace Jalle19\StatusManager;
4
5
use Jalle19\StatusManager\Database;
6
use Jalle19\StatusManager\Event\ConnectionSeenEvent;
7
use Jalle19\StatusManager\Event\Events;
8
use Jalle19\StatusManager\Event\InputSeenEvent;
9
use Jalle19\StatusManager\Event\InstanceSeenEvent;
10
use Jalle19\StatusManager\Event\InstanceStateEvent;
11
use Jalle19\StatusManager\Event\InstanceStatusUpdatesEvent;
12
use Jalle19\StatusManager\Event\SubscriptionSeenEvent;
13
use Jalle19\StatusManager\Event\SubscriptionStateChangeEvent;
14
use Jalle19\StatusManager\Subscription\StateChangeParser;
15
use Psr\Log\LoggerInterface;
16
use React\EventLoop\Factory;
17
use Symfony\Component\EventDispatcher\EventDispatcher;
18
19
/**
20
 * Class StatusManager
21
 * @package   Jalle19\StatusManager
22
 * @copyright Copyright &copy; Sam Stenvall 2015-
23
 * @license   https://www.gnu.org/licenses/gpl.html The GNU General Public License v2.0
24
 */
25
class StatusManager
26
{
27
28
	/**
29
	 * @var Configuration the configuration
30
	 */
31
	private $_configuration;
32
33
	/**
34
	 * @var LoggerInterface the logger
35
	 */
36
	private $_logger;
37
38
	/**
39
	 * @var InstanceStateManager
40
	 */
41
	private $_instanceStateManager;
42
43
	/**
44
	 * @var WebSocketManager
45
	 */
46
	private $_webSocketManager;
47
48
	/**
49
	 * @var EventDispatcher
50
	 */
51
	private $_eventDispatcher;
52
53
	/**
54
	 * @var PersistenceManager the persistence manager
55
	 */
56
	private $_persistenceManager;
57
58
59
	/**
60
	 * StatusManager constructor.
61
	 *
62
	 * @param Configuration   $configuration
63
	 * @param LoggerInterface $logger
64
	 */
65
	public function __construct(Configuration $configuration, LoggerInterface $logger)
66
	{
67
		$this->_configuration = $configuration;
68
		$this->_logger        = $logger;
69
	}
70
71
72
	/**
73
	 * Runs the application
74
	 */
75
	public function run()
76
	{
77
		// Configure the main event loop
78
		$eventLoop = Factory::create();
79
		$eventLoop->addPeriodicTimer($this->_configuration->getUpdateInterval(),
1 ignored issue
show
Documentation introduced by
$this->_configuration->getUpdateInterval() is of type double, but the function expects a object<React\EventLoop\numeric>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
80
			[$this, 'handleInstanceUpdates']);
81
82
		// Configure managers
83
		$this->_instanceStateManager = new InstanceStateManager($this->_logger, $this->_configuration->getInstances());
84
		$this->_webSocketManager     = new WebSocketManager($this->_logger, $this->_configuration, $eventLoop);
85
		$this->_persistenceManager   = new PersistenceManager($this->_logger);
86
87
		$this->configureEventDispatcher();
88
89
		$this->_eventDispatcher->dispatch(Events::MAIN_LOOP_STARTING);
90
		$eventLoop->run();
91
	}
92
93
94
	/**
95
	 * Configures the event dispatcher and attaches event listeners to it
96
	 */
97
	private function configureEventDispatcher()
98
	{
99
		$this->_eventDispatcher = new EventDispatcher();
100
101
		$eventDefinitions = [
102
			[Events::MAIN_LOOP_STARTING, $this, 'onMainLoopStarted'],
103
			[Events::MAIN_LOOP_STARTING, $this->_persistenceManager, 'onMainLoopStarted'],
104
			[Events::MAIN_LOOP_STARTING, $this->_webSocketManager, 'onMainLoopStarted'],
105
			[Events::INSTANCE_STATUS_UPDATES, $this->_webSocketManager, 'onInstanceStatusUpdates'],
106
			[Events::INSTANCE_STATE_REACHABLE, $this->_instanceStateManager, 'onInstanceReachable'],
107
			[Events::INSTANCE_STATE_UNREACHABLE, $this->_instanceStateManager, 'onInstanceUnreachable'],
108
			[Events::INSTANCE_STATE_MAYBE_REACHABLE, $this->_instanceStateManager, 'onInstanceMaybeReachable'],
109
			[Events::INSTANCE_SEEN, $this->_persistenceManager, 'onInstanceSeen'],
110
			[Events::CONNECTION_SEEN, $this->_persistenceManager, 'onConnectionSeen'],
111
			[Events::INPUT_SEEN, $this->_persistenceManager, 'onInputSeen'],
112
			[Events::SUBSCRIPTION_SEEN, $this->_persistenceManager, 'onSubscriptionSeen'],
113
			[Events::SUBSCRIPTION_STATE_CHANGE, $this->_persistenceManager, 'onSubscriptionStateChange'],
114
		];
115
116
		foreach ($eventDefinitions as $eventDefinition)
117
			$this->_eventDispatcher->addListener($eventDefinition[0], [$eventDefinition[1], $eventDefinition[2]]);
118
	}
119
120
121
	/**
122
	 * Called right before the main loop is started
123
	 */
124
	public function onMainLoopStarted()
125
	{
126
		// Log information about the database
127
		$this->_logger->debug('Using database at {databasePath}', [
128
			'databasePath' => $this->_configuration->getDatabasePath(),
129
		]);
130
131
		// Log information about the configured instances
132
		$instances = $this->_configuration->getInstances();
133
134
		$this->_logger->info('Managing {instances} instances:', [
135
			'instances' => count($instances),
136
		]);
137
138
		foreach ($instances as $configuredInstance)
139
		{
140
			$instance = $configuredInstance->getInstance();
141
142
			$this->_logger->info('  {address}:{port}', [
143
				'address' => $instance->getHostname(),
144
				'port'    => $instance->getPort(),
145
			]);
146
147
			$this->_eventDispatcher->dispatch(Events::INSTANCE_SEEN, new InstanceSeenEvent($instance));
148
		}
149
	}
150
151
152
	/**
153
	 * Handles the updates polled from the instances
154
	 */
155
	public function handleInstanceUpdates()
156
	{
157
		$statusCollection = $this->getStatusMessages();
158
159
		foreach ($statusCollection->getInstanceStatuses() as $instanceStatus)
160
		{
161
			$instanceName = $instanceStatus->getInstanceName();
162
163
			$this->_logger->debug('Got status updates from {instanceName}', [
164
				'instanceName' => $instanceName,
165
			]);
166
167
			// Persist connections
168
			foreach ($instanceStatus->getConnections() as $connection)
169
			{
170
				$this->_eventDispatcher->dispatch(Events::CONNECTION_SEEN,
171
					new ConnectionSeenEvent($instanceName, $connection));
172
			}
173
174
			// Persist inputs
175
			foreach ($instanceStatus->getInputs() as $input)
176
				$this->_eventDispatcher->dispatch(Events::INPUT_SEEN, new InputSeenEvent($instanceName, $input));
177
178
			// Persist running subscriptions
179
			foreach ($instanceStatus->getSubscriptions() as $subscription)
180
			{
181
				$this->_eventDispatcher->dispatch(Events::SUBSCRIPTION_SEEN,
182
					new SubscriptionSeenEvent($instanceName, $subscription));
183
			}
184
185
			// Handle subscription state changes
186
			foreach ($instanceStatus->getSubscriptionStateChanges() as $subscriptionStateChange)
187
			{
188
				$this->_eventDispatcher->dispatch(Events::SUBSCRIPTION_STATE_CHANGE,
189
					new SubscriptionStateChangeEvent($instanceName, $subscriptionStateChange));
190
			}
191
		}
192
193
		$this->_eventDispatcher->dispatch(Events::INSTANCE_STATUS_UPDATES,
194
			new InstanceStatusUpdatesEvent($statusCollection));
195
	}
196
197
198
	/**
199
	 * Retrieves and returns all status messages for the configured
200
	 * instances
201
	 * @return InstanceStatusCollection
202
	 */
203
	private function getStatusMessages()
204
	{
205
		$instances  = $this->_instanceStateManager->getInstances();
206
		$collection = new InstanceStatusCollection();
207
208
		foreach ($instances as $instance)
209
		{
210
			/* @var Instance $instance */
211
			$tvheadend    = $instance->getInstance();
212
			$instanceName = $instance->getName();
213
214
			// Collect statuses from currently reachable instances
215
			if ($this->_instanceStateManager->isReachable($instance))
216
			{
217
				try
218
				{
219
					$collection->add(new InstanceStatus(
220
						$instanceName,
221
						$tvheadend->getInputStatus(),
222
						$tvheadend->getSubscriptionStatus(),
223
						$tvheadend->getConnectionStatus(),
224
						StateChangeParser::parseStateChanges($tvheadend->getLogMessages())));
225
226
					$this->_eventDispatcher->dispatch(Events::INSTANCE_STATE_REACHABLE,
227
						new InstanceStateEvent($instance));
228
				}
229
				catch (\Exception $e)
230
				{
231
					$this->_eventDispatcher->dispatch(Events::INSTANCE_STATE_UNREACHABLE,
232
						new InstanceStateEvent($instance));
233
				}
234
			}
235
			else
236
			{
237
				$this->_eventDispatcher->dispatch(Events::INSTANCE_STATE_MAYBE_REACHABLE,
238
					new InstanceStateEvent($instance));
239
			}
240
		}
241
242
		return $collection;
243
	}
244
245
}
246