Completed
Push — master ( ea20ea...a25393 )
by Timo
41s
created

SessionMonitor::startSubscriptions()   B

Complexity

Conditions 3
Paths 1

Size

Total Lines 26
Code Lines 15

Duplication

Lines 0
Ratio 0 %

Importance

Changes 9
Bugs 2 Features 1
Metric Value
c 9
b 2
f 1
dl 0
loc 26
rs 8.8571
cc 3
eloc 15
nc 1
nop 0
1
<?php
2
3
/*
4
 * This file is part of the Tidal/WampWatch package.
5
 *   (c) 2016 Timo Michna <timomichna/yahoo.de>
6
 *
7
 *  For the full copyright and license information, please view the LICENSE
8
 *  file that was distributed with this source code.
9
 */
10
11
namespace Tidal\WampWatch;
12
13
use Evenement\EventEmitterInterface;
14
use Tidal\WampWatch\ClientSessionInterface as ClientSession;
15
16
/**
17
 * Description of SessionMonitor.
18
 *
19
 * @author Timo
20
 */
21
class SessionMonitor implements MonitorInterface, EventEmitterInterface
22
{
23
    use MonitorTrait {
24
        start as doStart;
25
        stop as doStop;
26
    }
27
28
    const SESSION_JOIN_TOPIC = 'wamp.session.on_join';
29
    const SESSION_LEAVE_TOPIC = 'wamp.session.on_leave';
30
    const SESSION_COUNT_TOPIC = 'wamp.session.count';
31
    const SESSION_LIST_TOPIC = 'wamp.session.list';
32
    const SESSION_INFO_TOPIC = 'wamp.session.get';
33
34
    protected $sessionIds = [];
35
36
    protected $joinSubscriptionId = false;
37
38
    protected $leaveSubscriptionId = false;
39
40
    protected $calledList = false;
41
42
    /**
43
     * Constructor.
44
     *
45
     * @param ClientSession $session
46
     */
47
    public function __construct(ClientSession $session)
48
    {
49
        $this->setClientSession($session);
50
    }
51
52
    /**
53
     * Start the monitor.
54
     *
55
     * @return bool
56
     */
57
    public function start()
58
    {
59
        $this->startSubscriptions();
60
        $this->retrieveSessionIds();
61
62
        return true;
63
    }
64
65
    /**
66
     * Checks if all necessary subscriptions and calls have been responded to.
67
     */
68
    protected function checkStarted()
69
    {
70
        if ($this->joinSubscriptionId > 0 &&
71
            $this->leaveSubscriptionId > 0 &&
72
            $this->calledList &&
73
            !$this->isRunning()
74
        ) {
75
            $this->doStart();
76
        }
77
    }
78
79
    /**
80
     * Stop the monitor.
81
     * Returns boolean wether the monitor could be started.
82
     *
83
     * @return bool
84
     */
85
    public function stop()
86
    {
87
        $this->stopSubscriptions();
88
        $this->doStop();
89
90
        return true;
91
    }
92
93
    /**
94
     * Retrieves the session-info for given sessionId
95
     * and populates it in via given callback.
96
     *
97
     * @param          $sessionId
98
     * @param callable $callback
99
     *
100
     * @return mixed
101
     */
102
    public function getSessionInfo($sessionId, callable $callback = null)
103
    {
104
        return $this->session->call(self::SESSION_INFO_TOPIC, [$sessionId])->then(
105
            function ($res) use ($callback) {
106
                $this->emit('info', [$res[0]]);
107
                if ($callback !== null) {
108
                    $callback($res[0]);
109
                }
110
            },
111
            function ($error) {
112
                $this->emit('error', [$error]);
113
            }
114
        );
115
    }
116
117
    /**
118
     * Retrieves the Ids of the sessions currently
119
     * registered on the wamp-router in the monitor's realm
120
     * and populates the data via given callback,.
121
     *
122
     * @param callable $callback
123
     *
124
     * @return mixed
125
     */
126
    public function getSessionIds(callable $callback)
127
    {
128
        if (!count($this->sessionIds)) {
129
            $this->retrieveSessionIds($callback);
130
131
            return;
132
        }
133
134
        $callback($this->sessionIds);
135
    }
136
137
    /**
138
     * Checks if a session id is known.
139
     *
140
     * @param $sessionId
141
     *
142
     * @return bool
143
     */
144
    public function hasSessionId($sessionId)
145
    {
146
        return array_search($sessionId, $this->sessionIds) !== false;
147
    }
148
149
    /**
150
     * Removes a session id.
151
     *
152
     * @param int $sessionId
153
     */
154
    protected function removeSessionId($sessionId)
155
    {
156
        if (!$this->hasSessionId($sessionId)) {
157
            return;
158
        }
159
        $key = array_search($sessionId, $this->sessionIds);
160
        unset($this->sessionIds[$key]);
161
        $this->sessionIds = array_values($this->sessionIds);
162
        $this->emit('leave', [$sessionId]);
163
    }
164
165
    /**
166
     * Checks if a session is known by extracting its id.
167
     *
168
     * @param $sessionInfo
169
     *
170
     * @return bool
171
     */
172
    protected function hasSession($sessionInfo)
173
    {
174
        return $this->hasSessionId($sessionInfo->session);
175
    }
176
177
    /**
178
     * Adds and publishes a joined session.
179
     *
180
     * @param $sessionInfo
181
     */
182
    protected function addSession($sessionInfo)
183
    {
184
        $this->sessionIds[] = $sessionInfo->session;
185
        $this->emit('join', [$sessionInfo]);
186
    }
187
188
    /**
189
     * Validates the sessionInfo sent from the router.
190
     *
191
     * @param string $sessionInfo
192
     *
193
     * @return bool
194
     */
195
    protected function validateSessionInfo($sessionInfo)
196
    {
197
        return is_object($sessionInfo) && property_exists($sessionInfo, 'session');
198
    }
199
200
    /**
201
     * Initializes the subscription to the meta-events.
202
     */
203
    protected function startSubscriptions()
204
    {
205
        // subscription to 'wamp.session.on_join'
206
        $this->session->subscribe(self::SESSION_JOIN_TOPIC, function (array $res) {
207
            $sessionInfo = $res[0];
208
            if (!$this->validateSessionInfo($sessionInfo) || $this->hasSession($sessionInfo)) {
209
                return;
210
            }
211
            $this->addSession($sessionInfo);
212
        })->then(function ($msg) {
213
            $this->joinSubscriptionId = $msg->getSubscriptionId();
214
            $this->checkStarted();
215
        });
216
217
        // subscription to 'wamp.session.on_leave'
218
        $this->session->subscribe(self::SESSION_LEAVE_TOPIC, function (array $res) {
219
            // @bug : wamp.session.on_leave is bugged as of crossbar.io 0.11.0
220
            // will provide sessionID when Browser closes/reloads,
221
            // but not when calling connection.close();
222
            $sessionId = (int) $res[0];
223
            $this->removeSessionId($sessionId);
224
        })->then(function ($msg) {
225
            $this->leaveSubscriptionId = $msg->getSubscriptionId();
226
            $this->checkStarted();
227
        });
228
    }
229
230
    /**
231
     * Unsubscribes from the meta-events.
232
     */
233
    protected function stopSubscriptions()
234
    {
235
        if ($this->joinSubscriptionId > 0) {
236
            Util::unsubscribe($this->session, $this->joinSubscriptionId);
237
        }
238
        if ($this->leaveSubscriptionId > 0) {
239
            Util::unsubscribe($this->session, $this->leaveSubscriptionId);
240
        }
241
    }
242
243
    /**
244
     * Retrieves the list of current sessionIds on the router.
245
     *
246
     * @param callable|null $callback
247
     */
248
    protected function retrieveSessionIds(callable $callback = null)
249
    {
250
        $this->session->call(self::SESSION_LIST_TOPIC, [])->then(
251
            function ($res) use ($callback) {
252
                // remove our own sessionID from the tracked sessions
253
                $sessionIds = $this->removeOwnSessionId($res[0]);
254
                $this->setList($sessionIds);
255
                $this->emit('list', [$this->getList()]);
256
                if ($callback !== null) {
257
                    $callback($this->sessionIds);
258
                }
259
                $this->calledList = true;
260
                $this->checkStarted();
261
            },
262
            function ($error) {
263
                $this->emit('error', [$error]);
264
            }
265
        );
266
    }
267
268
    protected function setList($list)
269
    {
270
        $this->sessionIds = $list;
271
    }
272
273
    protected function getList()
274
    {
275
        return $this->sessionIds;
276
    }
277
278
    /**
279
     * remove the sessionID of the Monitor from the list.
280
     *
281
     * @param array $sessionsIds
282
     *
283
     * @return mixed
284
     */
285
    protected function removeOwnSessionId(array $sessionsIds)
286
    {
287
        $key = array_search($this->session->getSessionId(), $sessionsIds);
288
        if ($key >= 0) {
289
            unset($sessionsIds[$key]);
290
            $sessionsIds = array_values($sessionsIds);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $sessionsIds. This often makes code more readable.
Loading history...
291
        }
292
293
        return $sessionsIds;
294
    }
295
}
296