Completed
Branch master (8e085e)
by Timo
02:38
created

SessionMonitor::checkStarted()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 9
rs 9.2
cc 4
eloc 5
nc 2
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
26
    const SESSION_JOIN_TOPIC = 'wamp.session.on_join';
27
    const SESSION_LEAVE_TOPIC = 'wamp.session.on_leave';
28
    const SESSION_COUNT_TOPIC = 'wamp.session.count';
29
    const SESSION_LIST_TOPIC = 'wamp.session.list';
30
    const SESSION_INFO_TOPIC = 'wamp.session.get';
31
32
    /**
33
     * @var array monitored session ids
34
     */
35
    protected $sessionIds = [];
36
37
    /**
38
     * @var int subscription id for on_join
39
     */
40
    protected $joinSubscriptionId = 0;
41
42
    /**
43
     * @var int subscription id for on_leave
44
     */
45
    protected $leaveSubscriptionId = 0;
46
47
    /**
48
     * Constructor.
49
     *
50
     * @param ClientSession $session
51
     */
52
    public function __construct(ClientSession $session)
53
    {
54
        $this->setClientSession($session);
55
        $this->initSetupCalls();
56
    }
57
58
    /**
59
     * Retrieves the session-info for given sessionId
60
     * and populates it in via given callback.
61
     *
62
     * @param          $sessionId
63
     * @param callable $callback
64
     *
65
     * @return mixed
66
     */
67
    public function getSessionInfo($sessionId, callable $callback = null)
68
    {
69
        return $this->session->call(self::SESSION_INFO_TOPIC, [$sessionId])->then(
70
            function ($res) use ($callback) {
71
                $this->emit('info', [$res[0]]);
72
                if ($callback !== null) {
73
                    $callback($res[0]);
74
                }
75
            },
76
            function ($error) {
77
                $this->emit('error', [$error]);
78
            }
79
        );
80
    }
81
82
    /**
83
     * Retrieves the Ids of the sessions currently
84
     * registered on the wamp-router in the monitor's realm
85
     * and populates the data via given callback,.
86
     *
87
     * @param callable $callback
88
     *
89
     * @return mixed
90
     */
91
    public function getSessionIds(callable $callback)
92
    {
93
        if (!count($this->sessionIds)) {
94
            $this->retrieveSessionIds($callback);
95
96
            return;
97
        }
98
99
        $callback($this->sessionIds);
100
    }
101
102
    /**
103
     * Checks if a session id is known.
104
     *
105
     * @param $sessionId
106
     *
107
     * @return bool
108
     */
109
    public function hasSessionId($sessionId)
110
    {
111
        return array_search($sessionId, $this->sessionIds) !== false;
112
    }
113
114
    /**
115
     * Removes a session id.
116
     *
117
     * @param int $sessionId
118
     */
119
    protected function removeSessionId($sessionId)
120
    {
121
        if (!$this->hasSessionId($sessionId)) {
122
            return;
123
        }
124
        $key = array_search($sessionId, $this->sessionIds);
125
        unset($this->sessionIds[$key]);
126
        $this->sessionIds = array_values($this->sessionIds);
127
        $this->emit('leave', [$sessionId]);
128
    }
129
130
    /**
131
     * Checks if a session is known by extracting its id.
132
     *
133
     * @param $sessionInfo
134
     *
135
     * @return bool
136
     */
137
    protected function hasSession($sessionInfo)
138
    {
139
        return $this->hasSessionId($sessionInfo->session);
140
    }
141
142
    /**
143
     * Adds and publishes a joined session.
144
     *
145
     * @param $sessionInfo
146
     */
147
    protected function addSession($sessionInfo)
148
    {
149
        $this->sessionIds[] = $sessionInfo->session;
150
        $this->emit('join', [$sessionInfo]);
151
    }
152
153
    /**
154
     * Validates the sessionInfo sent from the router.
155
     *
156
     * @param string $sessionInfo
157
     *
158
     * @return bool
159
     */
160
    protected function validateSessionInfo($sessionInfo)
161
    {
162
        return is_object($sessionInfo) && property_exists($sessionInfo, 'session');
163
    }
164
165
    /**
166
     * Initializes the subscription to the meta-events.
167
     */
168
    protected function initSetupCalls()
169
    {
170
        // @var \Tidal\WampWatch\Subscription\Collection
171
        $collection = $this->getSubscriptionCollection();
172
173
        $collection->addSubscription(self::SESSION_JOIN_TOPIC, function (array $res) {
174
            $sessionInfo = $res[0];
175
            if (!$this->validateSessionInfo($sessionInfo) || $this->hasSession($sessionInfo)) {
176
                return;
177
            }
178
            $this->addSession($sessionInfo);
179
        });
180
181
        $collection->addSubscription(self::SESSION_LEAVE_TOPIC, function (array $res) {
182
            // @bug : wamp.session.on_leave is bugged as of crossbar.io 0.11.0
183
            // will provide sessionID when Browser closes/reloads,
184
            // but not when calling connection.close();
185
            $sessionId = (int) $res[0];
186
            $this->removeSessionId($sessionId);
187
        });
188
189
        $this->setInitialCall(self::SESSION_LIST_TOPIC, $this->getSessionIdRetrievalCallback());
190
    }
191
192
    /**
193
     * Retrieves the list of current sessionIds on the router.
194
     *
195
     * @param callable|null $callback
196
     */
197
    protected function retrieveSessionIds(callable $callback = null)
198
    {
199
        $this->session->call(self::SESSION_LIST_TOPIC, [])
200
            ->then(
201
                $this->getSessionIdRetrievalCallback()
202
            )->done(function ($res) use ($callback) {
203
                if ($callback !== null) {
204
                    $callback($res);
205
                }
206
            });
207
    }
208
209
    protected function getSessionIdRetrievalCallback()
210
    {
211
        return function ($res) {
212
            // remove our own sessionID from the tracked sessions
213
            $sessionIds = $this->removeOwnSessionId($res[0]);
214
            $this->setList($sessionIds);
215
            $this->emit('list', [$this->getList()]);
216
            $this->checkStarted();
217
218
            return $this->getList();
219
        };
220
    }
221
222
    protected function setList($list)
223
    {
224
        $this->sessionIds = $list;
225
    }
226
227
    protected function getList()
228
    {
229
        return $this->sessionIds;
230
    }
231
232
    /**
233
     * remove the sessionID of the Monitor from the list.
234
     *
235
     * @param array $sessionsIds
236
     *
237
     * @return mixed
238
     */
239
    protected function removeOwnSessionId(array $sessionsIds)
240
    {
241
        $key = array_search($this->session->getSessionId(), $sessionsIds);
242
        if ($key >= 0) {
243
            unset($sessionsIds[$key]);
244
            $sessionsIds = array_values($sessionsIds);
245
        }
246
247
        return $sessionsIds;
248
    }
249
}
250