Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 61 additions & 41 deletions src/Discord/Discord.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
use Ratchet\Client\Connector;
use Ratchet\Client\WebSocket;
use Ratchet\RFC6455\Messaging\Message;
use React\Dns\Config\Config as DnsConfig;
use React\EventLoop\Loop;
use React\EventLoop\LoopInterface;
use React\EventLoop\TimerInterface;
Expand Down Expand Up @@ -95,6 +96,29 @@
* @property PrivateChannelRepository $private_channels
* @property SoundRepository $sounds
* @property UserRepository $users
*
* @property array $options
* @property string $options['token']
* @property LoggerInterface $options['logger']
* @property LoopInterface $options['loop']
* @property array|bool $options['loadAllMembers']
* @property array $options['disabledEvents']
* @property bool $options['storeMessages']
* @property array|bool $options['retrieveBans']
* @property int|null $options['large_threshold']
* @property array|null $options['shard']
* @property int|null $options['shard_id']
* @property int|null $options['num_shards']
* @property int|null $options['shardId']
* @property int|null $options['shardCount']
* @property array|null $options['presence']
* @property int $options['intents']
* @property array $options['socket_options']
* @property DnsConfig|string $options['dnsConfig']
* @property array $options['cache']
* @property string $options['collection']
* @property bool $options['useTransportCompression']
* @property bool $options['usePayloadCompression']
*/
class Discord
{
Expand Down Expand Up @@ -1690,7 +1714,8 @@ protected function resolveOptions(array $options = []): array
'usePayloadCompression',
])
->setDefaults([
'logger' => null,
'loop' => Loop::get(),
'logger' => new Monolog('DiscordPHP', [(new StreamHandler('php://stdout', Level::Debug))->setFormatter(new LineFormatter(null, null, true, true))]),
'loadAllMembers' => false,
'disabledEvents' => [],
'storeMessages' => false,
Expand Down Expand Up @@ -1724,8 +1749,42 @@ protected function resolveOptions(array $options = []): array
->setAllowedTypes('shardCount', ['null', 'int'])
->setAllowedTypes('presence', ['null', 'array'])
->setAllowedTypes('intents', ['array', 'int'])
->setNormalizer('intents', function ($options, $value) {
if (is_array($value)) {
$intent = 0;
$validIntents = Intents::getValidIntents();

foreach ($value as $idx => $i) {
if (! in_array($i, $validIntents)) {
throw new IntentException('Given intent at index '.$idx.' is invalid.');
}

$intent |= $i;
}

$value = $intent;
}

return (int) $value;
})
->setAllowedTypes('socket_options', 'array')
->setAllowedTypes('dnsConfig', ['string', \React\Dns\Config\Config::class])
->setNormalizer('socket_options', function ($options, $value) {
// Discord doesn't currently support IPv6. This prevents xdebug from catching exceptions when trying to fetch IPv6 for Discord.
$value['happy_eyeballs'] = false;

return $value;
})
->setAllowedTypes('dnsConfig', ['string', DnsConfig::class])
->setNormalizer('dnsConfig', function ($options, $value) {
if (null === $value) {
$value = DnsConfig::loadSystemConfigBlocking();
if (! $value->nameservers) {
$value->nameservers[] = '8.8.8.8';
}
}

return $value;
})
Comment on lines +1777 to +1787
Copy link

Copilot AI Jan 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'dnsConfig' option needs a default value in the setDefaults() configuration. Currently, 'dnsConfig' is defined but has no default, which means if a user doesn't provide it, the option will be undefined and the normalizer's null check won't be reached. Add 'dnsConfig' => null, to the setDefaults array around line 1717, and update setAllowedTypes on line 1790 to include 'null' as an allowed type: ->setAllowedTypes('dnsConfig', ['null', 'string', DnsConfig::class]).

Copilot uses AI. Check for mistakes.
->setAllowedTypes('collection', 'string')
->setNormalizer('collection', function ($options, $value) {
if (is_string($value) && class_exists($value) && is_subclass_of($value, ExCollectionInterface::class)) {
Expand All @@ -1751,50 +1810,11 @@ protected function resolveOptions(array $options = []): array

$options = $resolver->resolve($options);

$options['loop'] ??= Loop::get();

if (null === $options['logger']) {
$streamHandler = new StreamHandler('php://stdout', Level::Debug);
$lineFormatter = new LineFormatter(null, null, true, true);
$streamHandler->setFormatter($lineFormatter);
$logger = new Monolog('DiscordPHP', [$streamHandler]);
$options['logger'] = $logger;
}

if (! isset($options['dnsConfig'])) {
$dnsConfig = \React\Dns\Config\Config::loadSystemConfigBlocking();
if (! $dnsConfig->nameservers) {
$dnsConfig->nameservers[] = '8.8.8.8';
}

$options['dnsConfig'] = $dnsConfig;
}

if (is_array($options['intents'])) {
$intent = 0;
$validIntents = Intents::getValidIntents();

foreach ($options['intents'] as $idx => $i) {
if (! in_array($i, $validIntents)) {
throw new IntentException('Given intent at index '.$idx.' is invalid.');
}

$intent |= $i;
}

$options['intents'] = $intent;
}

if ($options['loadAllMembers'] && ! ($options['intents'] & Intents::GUILD_MEMBERS)) {
throw new IntentException('You have enabled the `loadAllMembers` option but have not enabled the required `GUILD_MEMBERS` intent.'.
'See the documentation on the `loadAllMembers` property for more information: http://discord-php.github.io/DiscordPHP/#basics');
}

// Discord doesn't currently support IPv6
// This prevents xdebug from catching exceptions when trying to fetch IPv6
// for Discord
$options['socket_options']['happy_eyeballs'] = false;

return $options;
}

Expand Down