Passed
Pull Request — master (#61)
by Timo
02:39
created

SessionMonitor::create()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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