Completed
Push — master ( b2dfe1...1412d2 )
by Sam
02:32
created

WebSocketManager::onMessage()   B

Complexity

Conditions 3
Paths 5

Size

Total Lines 24
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 24
rs 8.9713
cc 3
eloc 11
nc 5
nop 2
1
<?php
2
3
namespace Jalle19\StatusManager\Manager;
4
5
use Jalle19\StatusManager\Application;
6
use Jalle19\StatusManager\Event\InstanceStatusUpdatesEvent;
7
use Jalle19\StatusManager\Exception\MalformedRequestException;
8
use Jalle19\StatusManager\Exception\UnknownRequestException;
9
use Jalle19\StatusManager\Message\Factory as MessageFactory;
10
use Jalle19\StatusManager\Message\StatusUpdatesMessage;
11
use Ratchet\ConnectionInterface;
12
use Ratchet\Http\HttpServer;
13
use Ratchet\MessageComponentInterface;
14
use Ratchet\Server\IoServer;
15
use Ratchet\WebSocket\WsServer;
16
use React\EventLoop\LoopInterface;
17
use React\Socket\Server as ServerSocket;
18
19
/**
20
 * Handles events related to the WebSocket. Events are either triggered from Ratchet (onOpen etc.)
21
 * or from the event dispatcher in StatusManager.
22
 *
23
 * @package   Jalle19\StatusManager
24
 * @copyright Copyright &copy; Sam Stenvall 2016-
25
 * @license   https://www.gnu.org/licenses/gpl.html The GNU General Public License v2.0
26
 */
27
class WebSocketManager extends AbstractManager implements MessageComponentInterface
28
{
29
30
	/**
31
	 * @var IoServer the Websocket server
32
	 */
33
	private $_websocket;
34
35
	/**
36
	 * @var \SplObjectStorage the connected clients
37
	 */
38
	private $_connectedClients;
39
40
41
	/**
42
	 * WebSocketManager constructor.
43
	 *
44
	 * @param Application   $application
45
	 * @param LoopInterface $loop
46
	 */
47
	public function __construct(Application $application, LoopInterface $loop)
48
	{
49
		parent::__construct($application);
50
51
		$this->_connectedClients = new \SplObjectStorage();
52
		$configuration           = $application->getConfiguration();
53
54
		// Create the socket to listen on
55
		$socket = new ServerSocket($loop);
56
		$socket->listen($configuration->getListenPort(), $configuration->getListenAddress());
57
58
		// Create the WebSocket server
59
		$this->_websocket = new IoServer(new HttpServer(new WsServer($this)), $socket, $loop);
60
	}
61
62
63
	/**
64
	 * Called right before the main loop is started
65
	 */
66
	public function onMainLoopStarted()
67
	{
68
		$configuration = $this->getApplication()->getConfiguration();
69
70
		$this->getApplication()->getLogger()->info('Starting the Websocket server on {address}:{port}', [
71
			'address' => $configuration->getListenAddress(),
72
			'port'    => $configuration->getListenPort(),
73
		]);
74
	}
75
76
77
	/**
78
	 * @param InstanceStatusUpdatesEvent $event
79
	 */
80
	public function onInstanceStatusUpdates(InstanceStatusUpdatesEvent $event)
81
	{
82
		$this->getApplication()->getLogger()->debug('Broadcasting statuses to all clients');
83
		$message = new StatusUpdatesMessage($event->getInstanceStatusCollection());
84
85
		foreach ($this->_connectedClients as $client)
86
		{
87
			/* @var ConnectionInterface $client */
88
			$client->send(json_encode($message));
89
		}
90
	}
91
92
93
	/**
94
	 * @inheritdoc
95
	 */
96
	public function onOpen(ConnectionInterface $conn)
97
	{
98
		$this->getApplication()->getLogger()->debug('Got client connection');
99
		$this->_connectedClients->attach($conn);
100
	}
101
102
103
	/**
104
	 * @inheritdoc
105
	 */
106
	public function onClose(ConnectionInterface $conn)
107
	{
108
		$this->getApplication()->getLogger()->debug('Got client disconnect');
109
		$this->_connectedClients->detach($conn);
110
	}
111
112
113
	/**
114
	 * @inheritdoc
115
	 */
116
	public function onError(ConnectionInterface $conn, \Exception $e)
117
	{
118
		// TODO: Implement onError() method.
119
	}
120
121
122
	/**
123
	 * Dispatches incoming client messages to the appropriate handlers
124
	 *
125
	 * @param ConnectionInterface $from
126
	 * @param string              $msg
127
	 */
128
	public function onMessage(ConnectionInterface $from, $msg)
129
	{
130
		$logger = $this->getApplication()->getLogger();
131
132
		try
133
		{
134
			$message = MessageFactory::factory($msg);
135
136
			$logger->debug('Got message from client (type: {messageType})', [
137
				'messageType' => $message->getType(),
138
			]);
139
		}
140
		catch (MalformedRequestException $e)
141
		{
142
			$logger->error('Got malformed message from client (reason: {reason})', [
143
				'reason' => $e->getMessage(),
144
			]);
145
		}
146
		catch (UnknownRequestException $e)
147
		{
148
			// The server itself sometimes sends out messages that are received here, hence debug
149
			$logger->debug('Got unknown message from client');
150
		}
151
	}
152
153
}
154