Completed
Pull Request — master (#20)
by Timo
02:50
created

SessionMonitor::stopSubscriptions()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 5
Bugs 1 Features 1
Metric Value
c 5
b 1
f 1
dl 0
loc 9
rs 9.6666
cc 3
eloc 5
nc 4
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
213
        })->then(function ($msg) {
214
            $this->joinSubscriptionId = $msg->getSubscriptionId();
215
            $this->checkStarted();
216
        });
217
218
        // subscription to 'wamp.session.on_leave'
219
        $this->session->subscribe(self::SESSION_LEAVE_TOPIC, function (array $res) {
220
            // @bug : wamp.session.on_leave is bugged as of crossbar.io 0.11.0
221
            // will provide sessionID when Browser closes/reloads,
222
            // but not when calling connection.close();
223
            $sessionId = (int)$res[0];
224
            $this->removeSessionId($sessionId);
225
226
        })->then(function ($msg) {
227
            $this->leaveSubscriptionId = $msg->getSubscriptionId();
228
            $this->checkStarted();
229
        });
230
    }
231
232
    /**
233
     * Unsubscribes from the meta-events.
234
     */
235
    protected function stopSubscriptions()
236
    {
237
        if ($this->joinSubscriptionId > 0) {
238
            Util::unsubscribe($this->session, $this->joinSubscriptionId);
239
        }
240
        if ($this->leaveSubscriptionId > 0) {
241
            Util::unsubscribe($this->session, $this->leaveSubscriptionId);
242
        }
243
    }
244
245
    /**
246
     * Retrieves the list of current sessionIds on the router.
247
     *
248
     * @param callable|null $callback
249
     */
250
    protected function retrieveSessionIds(callable $callback = null)
251
    {
252
        $this->session->call(self::SESSION_LIST_TOPIC, [])->then(
253
            function ($res) use ($callback) {
254
                // remove our own sessionID from the tracked sessions
255
                $sessionIds = $this->removeOwnSessionId($res[0]);
256
                $this->setList($sessionIds);
257
                $this->emit('list', [$this->getList()]);
258
                if ($callback !== null) {
259
                    $callback($this->sessionIds);
260
                }
261
                $this->calledList = true;
262
                $this->checkStarted();
263
            },
264
            function ($error) {
265
                $this->emit('error', [$error]);
266
            }
267
        );
268
    }
269
270
    protected function setList($list)
271
    {
272
        $this->sessionIds = $list;
273
    }
274
275
    protected function getList()
276
    {
277
        return $this->sessionIds;
278
    }
279
280
    /**
281
     * remove the sessionID of the Monitor from the list.
282
     *
283
     * @param array $sessionsIds
284
     *
285
     * @return mixed
286
     */
287
    protected function removeOwnSessionId(array $sessionsIds)
288
    {
289
        $key = array_search($this->session->getSessionId(), $sessionsIds);
290
        if ($key >= 0) {
291
            unset($sessionsIds[$key]);
292
            $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...
293
        }
294
295
        return $sessionsIds;
296
    }
297
}
298