Completed
Push — master ( 2651dd...a129fb )
by Timo
23s
created

SessionMonitor::getSessionIdRetrievalCallback()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 1
eloc 8
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
12
namespace Tidal\WampWatch;
13
14
use Evenement\EventEmitterInterface;
15
use Tidal\WampWatch\ClientSessionInterface as ClientSession;
16
17
/**
18
 * Description of SessionMonitor.
19
 *
20
 * @author Timo
21
 */
22
class SessionMonitor implements MonitorInterface, EventEmitterInterface
23
{
24
    use MonitorTrait {
25
        start as doStart;
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
    /**
35
     * @var array monitored session ids
36
     */
37
    protected $sessionIds = [];
38
39
    /**
40
     * @var int subscription id for on_join
41
     */
42
    protected $joinSubscriptionId = 0;
43
44
    /**
45
     * @var int subscription id for on_leave
46
     */
47
    protected $leaveSubscriptionId = 0;
48
49
    /**
50
     * @var bool flag if list call has returned
51
     */
52
    protected $calledList = false;
53
54
    /**
55
     * Constructor.
56
     *
57
     * @param ClientSession $session
58
     */
59
    public function __construct(ClientSession $session)
60
    {
61
        $this->setClientSession($session);
62
    }
63
64
    /**
65
     * Start the monitor.
66
     *
67
     * @return bool
68
     */
69
    public function start()
70
    {
71
        $this->initSetupCalls();
72
        $this->getSubscriptionCollection()->subscribe()->done(function () {
73
            $this->checkStarted();
74
        });
75
        $this->retrieveSessionIds();
76
77
        return true;
78
    }
79
80
    /**
81
     * Checks if all necessary subscriptions and calls have been responded to.
82
     */
83
    protected function checkStarted()
84
    {
85
        if ($this->getSubscriptionCollection()->isSubscribed() &&
86
            $this->calledList &&
87
            !$this->isRunning()
88
        ) {
89
            $this->doStart();
90
        }
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 initSetupCalls()
204
    {
205
        // @var \Tidal\WampWatch\Subscription\Collection
206
        $collection = $this->getSubscriptionCollection();
207
208
        $collection->addSubscription(self::SESSION_JOIN_TOPIC, function (array $res) {
209
            $sessionInfo = $res[0];
210
            if (!$this->validateSessionInfo($sessionInfo) || $this->hasSession($sessionInfo)) {
211
                return;
212
            }
213
            $this->addSession($sessionInfo);
214
        });
215
216
        $collection->addSubscription(self::SESSION_LEAVE_TOPIC, function (array $res) {
217
            // @bug : wamp.session.on_leave is bugged as of crossbar.io 0.11.0
218
            // will provide sessionID when Browser closes/reloads,
219
            // but not when calling connection.close();
220
            $sessionId = (int) $res[0];
221
            $this->removeSessionId($sessionId);
222
        });
223
224
        $this->setInitialCall(self::SESSION_LIST_TOPIC, $this->getSessionIdRetrievalCallback());
225
    }
226
227
    /**
228
     * Retrieves the list of current sessionIds on the router.
229
     *
230
     * @param callable|null $callback
231
     */
232
    protected function retrieveSessionIds(callable $callback = null)
233
    {
234
        $this->session->call(self::SESSION_LIST_TOPIC, [])
235
            ->then(
236
                $this->getSessionIdRetrievalCallback()
237
            )->done(function ($res) use ($callback) {
238
                if ($callback !== null) {
239
                    $callback($res);
240
                }
241
            });
242
    }
243
244
    protected function getSessionIdRetrievalCallback()
245
    {
246
        return function ($res) {
247
            // remove our own sessionID from the tracked sessions
248
            $sessionIds = $this->removeOwnSessionId($res[0]);
249
            $this->setList($sessionIds);
250
            $this->emit('list', [$this->getList()]);
251
            $this->calledList = true;
252
            $this->checkStarted();
253
254
            return $this->getList();
255
        };
256
    }
257
258
    protected function setList($list)
259
    {
260
        $this->sessionIds = $list;
261
    }
262
263
    protected function getList()
264
    {
265
        return $this->sessionIds;
266
    }
267
268
    /**
269
     * remove the sessionID of the Monitor from the list.
270
     *
271
     * @param array $sessionsIds
272
     *
273
     * @return mixed
274
     */
275
    protected function removeOwnSessionId(array $sessionsIds)
276
    {
277
        $key = array_search($this->session->getSessionId(), $sessionsIds);
278
        if ($key >= 0) {
279
            unset($sessionsIds[$key]);
280
            $sessionsIds = array_values($sessionsIds);
281
        }
282
283
        return $sessionsIds;
284
    }
285
}
286