Completed
Push — master ( 098987...2e6749 )
by Sam
02:27
created

StatusManager::onMainLoopTick()   B

Complexity

Conditions 6
Paths 17

Size

Total Lines 45
Code Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 45
rs 8.439
cc 6
eloc 21
nc 17
nop 0
1
<?php
2
3
namespace Jalle19\StatusManager\Manager;
4
5
use Jalle19\StatusManager\Configuration\Instance;
6
use Jalle19\StatusManager\Event\ConnectionSeenEvent;
7
use Jalle19\StatusManager\Event\Events;
8
use Jalle19\StatusManager\Event\InputSeenEvent;
9
use Jalle19\StatusManager\Event\InstanceStatusCollectionRequestEvent;
10
use Jalle19\StatusManager\Event\InstanceSeenEvent;
11
use Jalle19\StatusManager\Event\InstanceStateEvent;
12
use Jalle19\StatusManager\Event\InstanceStatusUpdatesEvent;
13
use Jalle19\StatusManager\Event\SubscriptionSeenEvent;
14
use Jalle19\StatusManager\Event\SubscriptionStateChangeEvent;
15
use Jalle19\StatusManager\Instance\InstanceStatus;
16
use Jalle19\StatusManager\Instance\InstanceStatusCollection;
17
use Jalle19\StatusManager\Subscription\StateChangeParser;
18
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
19
20
/**
21
 * Class StatusManager
22
 * @package   Jalle19\StatusManager\Manager
23
 * @copyright Copyright &copy; Sam Stenvall 2015-
24
 * @license   https://www.gnu.org/licenses/gpl.html The GNU General Public License v2.0
25
 */
26
class StatusManager extends AbstractManager implements EventSubscriberInterface
27
{
28
29
	/**
30
	 * @inheritdoc
31
	 */
32
	public static function getSubscribedEvents()
33
	{
34
		return [
35
			Events::MAIN_LOOP_STARTING => 'onMainLoopStarted',
36
		];
37
	}
38
39
40
	/**
41
	 * Called right before the main loop is started
42
	 */
43
	public function onMainLoopStarted()
44
	{
45
		// Log information about the database
46
		$this->logger->debug('Using database at {databasePath}', [
47
			'databasePath' => $this->configuration->getDatabasePath(),
48
		]);
49
50
		// Log information about the configured instances
51
		$instances = $this->configuration->getInstances();
52
53
		$this->logger->info('Managing {instances} instances:', [
54
			'instances' => count($instances),
55
		]);
56
57
		foreach ($instances as $configuredInstance)
58
		{
59
			$instance = $configuredInstance->getInstance();
60
61
			$this->logger->info('  {address}:{port}', [
62
				'address' => $instance->getHostname(),
63
				'port'    => $instance->getPort(),
64
			]);
65
66
			$this->eventDispatcher->dispatch(Events::INSTANCE_SEEN, new InstanceSeenEvent($instance));
67
		}
68
	}
69
70
71
	/**
72
	 * Called periodically by the event loop. Here we inform the instance state manager
73
	 * that it should send us the current set of instances and their respective state.
74
	 */
75
	public function onMainLoopTick()
76
	{
77
		/* @var InstanceStatusCollectionRequestEvent $event */
78
		$event = $this->eventDispatcher->dispatch(Events::INSTANCE_STATUS_COLLECTION_REQUEST,
79
			new InstanceStatusCollectionRequestEvent());
80
81
		$statusCollection = $this->getStatusMessages($event->getInstanceStatusCollection());
82
83
		foreach ($statusCollection->getInstanceStatuses() as $instanceStatus)
84
		{
85
			$instanceName = $instanceStatus->getInstanceName();
86
87
			$this->logger->debug('Got status updates from {instanceName}', [
88
				'instanceName' => $instanceName,
89
			]);
90
91
			// Persist connections
92
			foreach ($instanceStatus->getConnections() as $connection)
93
			{
94
				$this->eventDispatcher->dispatch(Events::CONNECTION_SEEN,
95
					new ConnectionSeenEvent($instanceName, $connection));
96
			}
97
98
			// Persist inputs
99
			foreach ($instanceStatus->getInputs() as $input)
100
				$this->eventDispatcher->dispatch(Events::INPUT_SEEN, new InputSeenEvent($instanceName, $input));
101
102
			// Persist running subscriptions
103
			foreach ($instanceStatus->getSubscriptions() as $subscription)
104
			{
105
				$this->eventDispatcher->dispatch(Events::SUBSCRIPTION_SEEN,
106
					new SubscriptionSeenEvent($instanceName, $subscription));
107
			}
108
109
			// Handle subscription state changes
110
			foreach ($instanceStatus->getSubscriptionStateChanges() as $subscriptionStateChange)
111
			{
112
				$this->eventDispatcher->dispatch(Events::SUBSCRIPTION_STATE_CHANGE,
113
					new SubscriptionStateChangeEvent($instanceName, $subscriptionStateChange));
114
			}
115
		}
116
117
		$this->eventDispatcher->dispatch(Events::INSTANCE_STATUS_UPDATES,
118
			new InstanceStatusUpdatesEvent($statusCollection));
119
	}
120
121
122
	/**
123
	 * Retrieves and returns all status messages for the configured
124
	 * instances
125
	 *
126
	 * @param \SplObjectStorage $instances the instances and their state
127
	 *
128
	 * @return InstanceStatusCollection
129
	 */
130
	private function getStatusMessages($instances)
131
	{
132
		$collection = new InstanceStatusCollection();
133
134
		foreach ($instances as $instance)
135
		{
136
			/* @var Instance $instance */
137
			$tvheadend     = $instance->getInstance();
138
			$instanceName  = $instance->getName();
139
			$instanceState = $instances[$instance];
140
141
			// Collect statuses from currently reachable instances
142
			if ($instanceState->isReachable())
143
			{
144
				try
145
				{
146
					$collection->add(new InstanceStatus(
147
						$instanceName,
148
						$tvheadend->getInputStatus(),
149
						$tvheadend->getSubscriptionStatus(),
150
						$tvheadend->getConnectionStatus(),
151
						StateChangeParser::parseStateChanges($tvheadend->getLogMessages())));
152
153
					$this->eventDispatcher->dispatch(Events::INSTANCE_STATE_REACHABLE,
154
						new InstanceStateEvent($instance));
155
				}
156
				catch (\Exception $e)
157
				{
158
					$this->eventDispatcher->dispatch(Events::INSTANCE_STATE_UNREACHABLE,
159
						new InstanceStateEvent($instance));
160
				}
161
			}
162
			else
163
			{
164
				$this->eventDispatcher->dispatch(Events::INSTANCE_STATE_MAYBE_REACHABLE,
165
					new InstanceStateEvent($instance));
166
			}
167
		}
168
169
		return $collection;
170
	}
171
172
}
173