Completed
Branch master (fafdd5)
by Cody
01:21
created

SetupCommand   A

Complexity

Total Complexity 9

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 5

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 9
lcom 1
cbo 5
dl 0
loc 138
ccs 0
cts 66
cp 0
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
B handle() 0 57 5
A getSocket() 0 4 1
A getGateway() 0 18 2
1
<?php
2
3
namespace NotificationChannels\Discord\Commands;
4
5
use Exception;
6
use WebSocket\Client;
7
use Illuminate\Support\Arr;
8
use Illuminate\Console\Command;
9
use GuzzleHttp\Client as HttpClient;
10
11
class SetupCommand extends Command
12
{
13
    /**
14
     * @var string
15
     */
16
    protected $signature = 'discord:setup';
17
18
    /**
19
     * @var string
20
     */
21
    protected $description = "Add the bot to your server(s) and identify it with Discord's gateway.";
22
23
    /**
24
     * @var \GuzzleHttp\Client
25
     */
26
    protected $guzzle;
27
28
    /**
29
     * @var string
30
     */
31
    protected $token = null;
32
33
    /**
34
     * @var string
35
     */
36
    protected $gateway = 'wss://gateway.discord.gg';
37
38
    /**
39
     * @param \GuzzleHttp\Client $guzzle
40
     * @param string|null $token
41
     */
42
    public function __construct(HttpClient $guzzle, $token = null)
43
    {
44
        parent::__construct();
45
46
        $this->guzzle = $guzzle;
47
        $this->token = $token;
48
    }
49
50
    /**
51
     * Attempt to connect and identify a bot with the Discord websocket gateway.
52
     *
53
     * @return int|void
54
     */
55
    public function handle()
56
    {
57
        if (! $this->token) {
58
            $this->error('You must paste your Discord token (App Bot User token) into your `services.php` config file.');
59
            $this->error('View the README for more info: https://github.com/laravel-notification-channels/discord#installation');
60
61
            return -1;
62
        }
63
64
        if (! $this->confirm('Is the bot already added to your server?')) {
65
            $clientId = $this->ask('What is your Discord app client ID?');
66
67
            $this->warn('Add the bot to your server by visiting this link: https://discordapp.com/oauth2/authorize?&client_id='.$clientId.'&scope=bot&permissions=0');
68
69
            if (! $this->confirm('Continue?', true)) {
70
                return -1;
71
            }
72
        }
73
74
        $this->warn("Attempting to identify the bot with Discord's websocket gateway...");
75
76
        $this->gateway = $this->getGateway();
77
78
        $this->warn("Connecting to '$this->gateway'...");
79
80
        $client = $this->getSocket($this->gateway);
81
82
        // Discord requires all bots to connect via a websocket connection and
83
        // identify at least once before any API requests over HTTP are allowed.
84
        // https://discordapp.com/developers/docs/topics/gateway#gateway-identify
85
        $client->send(json_encode([
86
            'op' => 2,
87
            'd' => [
88
                'token' => $this->token,
89
                'v' => 3,
90
                'compress' => false,
91
                'properties' => [
92
                    '$os' => PHP_OS,
93
                    '$browser' => 'laravel-notification-channels-discord',
94
                    '$device' => 'laravel-notification-channels-discord',
95
                    '$referrer' => '',
96
                    '$referring_domain' => '',
97
                ],
98
            ],
99
        ]));
100
101
        $response = $client->receive();
102
        $identified = Arr::get(json_decode($response, true), 't') === 'READY';
103
104
        if (! $identified) {
105
            $this->error("Discord responded with an error while trying to identify the bot: $response");
106
107
            return -1;
108
        }
109
110
        $this->info('Your bot has been identified by Discord and can now send API requests!');
111
    }
112
113
    /**
114
     * Get a websocket client for the given gateway.
115
     *
116
     * @param string $gateway
117
     *
118
     * @return \WebSocket\Client
119
     */
120
    public function getSocket($gateway)
121
    {
122
        return new Client($gateway);
123
    }
124
125
    /**
126
     * Get the URL of the gateway that the socket should connect to.
127
     *
128
     * @return string
129
     */
130
    public function getGateway()
131
    {
132
        $gateway = $this->gateway;
133
134
        try {
135
            $response = $this->guzzle->get('https://discordapp.com/api/gateway', [
136
                'headers' => [
137
                    'Authorization' => 'Bot '.$this->token,
138
                ],
139
            ]);
140
141
            $gateway = Arr::get(json_decode($response->getBody(), true), 'url', $gateway);
142
        } catch (Exception $e) {
143
            $this->warn("Could not get a websocket gateway address, defaulting to '{$gateway}'.");
144
        }
145
146
        return $gateway;
147
    }
148
}
149