CentrifugoBroadcaster::__construct()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Opekunov\Centrifugo;
6
7
use Exception;
8
use Illuminate\Broadcasting\Broadcasters\Broadcaster;
9
use Illuminate\Broadcasting\BroadcastException;
10
use Symfony\Component\HttpKernel\Exception\HttpException;
11
12
class CentrifugoBroadcaster extends Broadcaster
13
{
14
    /**
15
     * The Centrifugo SDK instance.
16
     *
17
     * @var Contracts\CentrifugoInterface
18
     */
19
    protected $centrifugo;
20
21
    /**
22
     * Create a new broadcaster instance.
23
     *
24
     * @param Centrifugo $centrifugo
25
     */
26
    public function __construct(Centrifugo $centrifugo)
27
    {
28
        $this->centrifugo = $centrifugo;
29
    }
30
31
    /**
32
     * Authenticate the incoming request for a given channel.
33
     *
34
     * @param \Illuminate\Http\Request $request
35
     *
36
     * @return mixed
37
     */
38
    public function auth($request)
39
    {
40
        if ($request->user()) {
41
            $client = $this->getClientFromRequest($request);
42
            $channels = $this->getChannelsFromRequest($request);
43
44
            $response = [];
45
            $privateResponse = [];
46
            foreach ($channels as $channel) {
47
                $channelName = $this->getChannelName($channel);
48
49
                try {
50
                    $isAccessGranted = $this->verifyUserCanAccessChannel($request, $channelName);
51
                } catch (HttpException $e) {
52
                    $isAccessGranted = false;
53
                }
54
55
                if ($private = $this->isPrivateChannel($channel)) {
56
                    $privateResponse['channels'][] = $this->makeResponseForPrivateClient($isAccessGranted, $channel, $client);
57
                } else {
58
                    $response[$channel] = $this->makeResponseForClient($isAccessGranted, $client);
59
                }
60
            }
61
62
            return response($private ? $privateResponse : $response);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $private seems to be defined by a foreach iteration on line 46. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
63
        } else {
64
            throw new HttpException(401);
65
        }
66
    }
67
68
    /**
69
     * Return the valid authentication response.
70
     *
71
     * @param \Illuminate\Http\Request $request
72
     * @param mixed                    $result
73
     *
74
     * @return mixed
75
     */
76
    public function validAuthenticationResponse($request, $result)
77
    {
78
        return $result;
79
    }
80
81
    /**
82
     * Broadcast the given event.
83
     *
84
     * @param array  $channels
85
     * @param string $event
86
     * @param array  $payload
87
     *
88
     * @return void
89
     */
90
    public function broadcast(array $channels, $event, array $payload = [])
91
    {
92
        $payload['event'] = $event;
93
        $channels = array_map(function ($channel) {
94
            return str_replace('private-', '$', (string) $channel);
95
        }, $channels);
96
97
        $response = $this->centrifugo->broadcast($this->formatChannels($channels), $payload);
98
99
        if (is_array($response) && !isset($response['error'])) {
100
            return;
101
        }
102
103
        throw new BroadcastException(
104
            $response['error'] instanceof Exception ? $response['error']->getMessage() : $response['error']['message'],
105
            $response['error'] instanceof Exception ? $response['error']->getCode() : $response['error']['code'],
106
        );
107
    }
108
109
    /**
110
     * Get client from request.
111
     *
112
     * @param \Illuminate\Http\Request $request
113
     *
114
     * @return string
115
     */
116
    private function getClientFromRequest($request)
117
    {
118
        return $request->get('client', '');
119
    }
120
121
    /**
122
     * Get channels from request.
123
     *
124
     * @param \Illuminate\Http\Request $request
125
     *
126
     * @return array
127
     */
128
    private function getChannelsFromRequest($request)
129
    {
130
        $channels = $request->get('channels', []);
131
132
        return is_array($channels) ? $channels : [$channels];
133
    }
134
135
    /**
136
     * Get channel name without $ symbol (if present).
137
     *
138
     * @param string $channel
139
     *
140
     * @return string
141
     */
142
    private function getChannelName(string $channel)
143
    {
144
        return $this->isPrivateChannel($channel) ? substr($channel, 1) : $channel;
145
    }
146
147
    /**
148
     * Check channel name by $ symbol.
149
     *
150
     * @param string $channel
151
     *
152
     * @return bool
153
     */
154
    private function isPrivateChannel(string $channel): bool
155
    {
156
        return substr($channel, 0, 1) === '$';
157
    }
158
159
    /**
160
     * Make response for client, based on access rights.
161
     *
162
     * @param bool   $access_granted
163
     * @param string $client
164
     *
165
     * @return array
166
     */
167
    private function makeResponseForClient(bool $access_granted, string $client)
168
    {
169
        $info = [];
170
171
        return $access_granted ? [
172
            'sign' => $this->centrifugo->generateConnectionToken($client, 0, $info),
173
            'info' => $info,
174
        ] : [
175
            'status' => 403,
176
        ];
177
    }
178
179
    /**
180
     * Make response for client, based on access rights of private channel.
181
     *
182
     * @param bool   $accessGranted
183
     * @param string $channel
184
     * @param string $client
185
     * @param bool   $showInfo
186
     *
187
     * @return array
188
     */
189
    private function makeResponseForPrivateClient(bool $accessGranted, string $channel, string $client)
190
    {
191
        $info = [];
192
        $showInfo = $this->centrifugo->showNodeInfo();
193
194
        return $accessGranted ? [
195
196
            'channel' => $channel,
197
            'token'   => $this->centrifugo->generatePrivateChannelToken($client, $channel, 0, $info),
198
            'info'    => $showInfo ? $this->centrifugo->info() : null,
199
200
        ] : [
201
            'status' => 403,
202
        ];
203
    }
204
}
205