Pushing changes
This commit is contained in:
14
node_modules/discordie/.npmignore
generated
vendored
Normal file
14
node_modules/discordie/.npmignore
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
.eslintrc
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
.idea
|
||||
.grunt
|
||||
.lock-wscript
|
||||
build/Release
|
||||
node_modules
|
||||
examples/auth.js
|
||||
examples/test.mp3
|
24
node_modules/discordie/LICENSE
generated
vendored
Normal file
24
node_modules/discordie/LICENSE
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
Copyright (c) 2015-2016, qeled
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
501
node_modules/discordie/changelog.md
generated
vendored
Normal file
501
node_modules/discordie/changelog.md
generated
vendored
Normal file
@ -0,0 +1,501 @@
|
||||
# Discordie changelog
|
||||
|
||||
## 2017-01-08, Version 0.11.0
|
||||
|
||||
#### New:
|
||||
|
||||
- GIF support in `IUser.avatarURL`, added `IUser.staticAvatarURL`;
|
||||
- Added `isGuildVoice`, `isGuildText`, `isDM`, `isGroupDM` getters to channels.
|
||||
|
||||
#### Fixed:
|
||||
|
||||
- Pending voice connections failing to create while already connecting;
|
||||
|
||||
|
||||
## 2016-12-01, Version 0.10.0
|
||||
|
||||
#### New:
|
||||
|
||||
- Reactions:
|
||||
- Events `MESSAGE_REACTION_ADD`, `MESSAGE_REACTION_REMOVE`,
|
||||
`MESSAGE_REACTION_REMOVE_ALL`;
|
||||
- Permission `ADD_REACTIONS`;
|
||||
- Methods:
|
||||
- **{Promise\<Array\<IUser>, Error>}** `IMessage.fetchReactions(emoji, limit, after)`;
|
||||
- **{Promise}** `IMessage.addReaction(emoji)`;
|
||||
- **{Promise}** `IMessage.removeReaction(emoji, user)`;
|
||||
- `IGuild.editEmoji` now supports arrays of `IRole`;
|
||||
- Embed support in messages: `ITextChannel.sendMessage(..., embed)`,
|
||||
`IMessage.edit(content, embed)`;
|
||||
- `IMessage.edit(content, ...)` now stringifies `content` if not string.
|
||||
|
||||
#### Fixed:
|
||||
|
||||
- Guild icon/splash/emoji url generators not using CDN endpoint;
|
||||
- Sharding option validation error messages are now more specific.
|
||||
|
||||
|
||||
## 2016-10-19, Version 0.9.0
|
||||
|
||||
#### New:
|
||||
|
||||
- Events `CHANNEL_UPDATE`, `GUILD_UPDATE`, `GUILD_MEMBER_UPDATE`,
|
||||
`GUILD_ROLE_UPDATE`, `GUILD_EMOJIS_UPDATE` now contain a function
|
||||
`getChanges()` for getting state object `{before, after}`;
|
||||
- Events `GUILD_DELETE`, `GUILD_MEMBER_REMOVE`, `GUILD_ROLE_DELETE`
|
||||
now contain a function `getCachedData()` for getting deleted state object;
|
||||
- Added `data` field to `GUILD_MEMBER_REMOVE` event;
|
||||
- Method `sendMessage` now converts into string any non-string input data;
|
||||
- Support for `"dnd"` and `"invisible"` statuses;
|
||||
- `IAuthenticatedUser.setStatus` now supports status object
|
||||
`{status: String, afk: Boolean}`;
|
||||
- Added `General` permissions: `MANAGE_WEBHOOKS`, `MANAGE_EMOJIS`;
|
||||
- Getter `IMessage.displayUsername` returning a username or nick if present;
|
||||
- Webhooks:
|
||||
- Event `WEBHOOKS_UPDATE`;
|
||||
- Message field **{String}** `IMessage.webhook_id`;
|
||||
- Getter **{Boolean}**`IUser.isWebhook`;
|
||||
- `IWebhookManager` as `Discordie.Webhooks`:
|
||||
- **{Promise\<Array\<Object>, Error>}** `fetchForGuild(guild)`;
|
||||
- **{Promise\<Array\<Object>, Error>}** `fetchForChannel(channel)`;
|
||||
- **{Promise\<Object, Error>}** `create(channel, options)`;
|
||||
- **{Promise\<Object, Error>}** `fetch(webhook, token)`;
|
||||
- **{Promise\<Object, Error>}** `edit(webhook, token, options)`;
|
||||
- **{Promise}** `delete(webhook, token)`;
|
||||
- **{Promise}** `execute(webhook, token, options, wait)`;
|
||||
- **{Promise}** `executeSlack(webhook, token, options, wait)`;
|
||||
- `IGuild` emoji methods (user accounts only):
|
||||
- **{Promise\<Array\<Object>, Error>}** `fetchEmoji()`;
|
||||
- **{Promise\<Object, Error>}** `uploadEmoji(image, name)`;
|
||||
- **{Promise}** `deleteEmoji(emoji)`;
|
||||
- **{Promise\<Object, Error>}** `editEmoji(emoji, options)`;
|
||||
- **{String|null}** `getEmojiURL(emoji)`;
|
||||
- Presence (status and game) can now be set before `GATEWAY_READY`;
|
||||
- Added param `userLimit` to method `IGuild.createChannel` and
|
||||
`IChannel.clone`;
|
||||
- Added `IGuild` field `default_message_notifications`;
|
||||
- Added params `roles`, `channels`, `verificationLevel`,
|
||||
`defaultMessageNotifications` to method `IGuild.create`;
|
||||
- Added param `defaultMessageNotifications` to method `IGuild.edit`;
|
||||
- `IGuild` widget properties `embed_enabled`, `embed_channel_id` have been
|
||||
replaced with methods `getWidget()` and `editWidget(options)`;
|
||||
|
||||
#### Fixed:
|
||||
|
||||
- Fixed `guild.member_count` being erased after `GUILD_UPDATE`;
|
||||
- Calling `JSON.stringify` on interfaces not converting internal
|
||||
`Map`s and `Set`s into arrays (ex. `roles` array in an `IGuild`);
|
||||
- Event `GUILD_MEMBER_REMOVE` no longer emits for self due to
|
||||
race condition between `GUILD_DELETE` and `GUILD_MEMBER_REMOVE`;
|
||||
- Fixed role reordering;
|
||||
- Fixed `IChannel.clone` not handling channel types correctly;
|
||||
|
||||
|
||||
## 2016-08-31, Version 0.8.1
|
||||
|
||||
- Minor changes in rate limit bucket structure, X-RateLimit-Reset support;
|
||||
- Calling `member.unban()` on invalid member objects no longer throws;
|
||||
- Added `CHANNEL_PINNED_MESSAGE` (type 6) to `Discordie.MessageTypes`.
|
||||
|
||||
## 2016-08-17, Version 0.8.0
|
||||
|
||||
#### Breaking Discord API v6 changes:
|
||||
|
||||
- Channel type is now a number, not string `"text"` and `"voice"`:
|
||||
see [`Discordie.ChannelTypes`](https://qeled.github.io/discordie/#/docs/IChannel);
|
||||
- Direct message channels now have **{Array\<IUser>}** `recipients`
|
||||
instead of **{String}** `recipient_id`, getter **{IUser}** `recipient`
|
||||
added and marked as deprecated;
|
||||
- Channel field `is_private` has been removed from the API,
|
||||
getters [`isPrivate` and `is_private`](https://qeled.github.io/discordie/#/docs/IChannel?p=IChannel%23is_private)
|
||||
added to replace it. Getter `is_private` is marked as deprecated.
|
||||
|
||||
#### Overview of API v6 changes:
|
||||
|
||||
- New events `CALL_CREATE`, `CALL_UPDATE`, `CALL_DELETE`,
|
||||
`CHANNEL_RECIPIENT_ADD`, `CHANNEL_RECIPIENT_REMOVE`;
|
||||
- Message fields added:
|
||||
- **{Number}** `type`:
|
||||
everything other than 0 is a system message,
|
||||
see [`Discordie.MessageTypes`](https://qeled.github.io/discordie/#/docs/IMessage);
|
||||
- **{Object}** `call`: [object](http://qeled.github.io/discordie/#/docs/IMessage?p=IMessage.call)
|
||||
present if this is a system message with call info.
|
||||
- Channel fields removed:
|
||||
**{String}** `type`,
|
||||
**{Boolean}** `is_private`;
|
||||
- Channel fields added:
|
||||
**{Number}** `type`,
|
||||
**{Array<IUser>}** `recipients`,
|
||||
**{String|null}** `owner_id`,
|
||||
**{String|null}** `icon`.
|
||||
|
||||
#### Library changes:
|
||||
|
||||
- New local events `CALL_UNAVAILABLE`, `CALL_RING`;
|
||||
- New method `IDirectMessageChannelCollection.createGroupDM()`;
|
||||
- **`IDirectMessageChannel`**:
|
||||
- New getters:
|
||||
- **{[ICall](http://qeled.github.io/discordie/#/docs/ICall)}** `call`;
|
||||
- **{Array<IUser>|null}** `usersInCall`;
|
||||
- **{IAuthenticatedUser|IUser|null}** `owner`;
|
||||
- **{String|null}** `iconURL`;
|
||||
- New methods:
|
||||
- **{Boolean}** `isOwner(user)`;
|
||||
- **{Promise}** `ring(recipients)` (user accounts only);
|
||||
- **{Promise}** `stopRinging(recipients)` (user accounts only);
|
||||
- **{Promise}** `changeCallRegion(region)` (user accounts only);
|
||||
- **{Promise}** `addRecipient(user)` (user accounts only);
|
||||
- **{Promise}** `removeRecipient(user)` (user accounts only);
|
||||
- **{Promise\<IDirectMessageChannel, Error>}** `setName(name)`;
|
||||
- **{Promise\<IDirectMessageChannel, Error>}** `setIcon(icon)`;
|
||||
- **{Promise}** `joinCall(selfMute, selfDeaf)` (user accounts only);
|
||||
- **{void}** `leaveCall()`;
|
||||
- **{VoiceConnectionInfo|null}** `getVoiceConnectionInfo()`;
|
||||
- **{Promise<ICall|null, Error>}** `fetchCall()`;
|
||||
- Marked getter `recipient` as deprecated, use `recipients` instead;
|
||||
- **`IMessage`**:
|
||||
- New getters:
|
||||
- **{Boolean|null}** `isSystem`;
|
||||
- **{String|null}** `systemMessage`;
|
||||
- `IUser.getVoiceChannel(guild)` now accepts null guild;
|
||||
- New method `IUserCollection.usersInCall(channel)`.
|
||||
|
||||
#### New:
|
||||
|
||||
- Option to disable implicit mentions in
|
||||
`user.isMentioned(message, ignoreImplicitMentions)`;
|
||||
- Bot token header is now forced depending on account type received in
|
||||
`READY`;
|
||||
- Updated rate limits, including header support.
|
||||
|
||||
#### Fixed:
|
||||
|
||||
- `channel.fetchMessages()` failing with Discord's new parameter validation
|
||||
(since 2016-08-11).
|
||||
|
||||
## 2016-08-04, Version 0.7.6
|
||||
|
||||
#### New:
|
||||
|
||||
- Emoji field support: `IGuild.emojis`;
|
||||
- Bot application and owner info: `IAuthenticatedUser.getApplication()`.
|
||||
|
||||
#### Other:
|
||||
|
||||
- `ICollectionBase.forEach` now doesn't stop iterating if you return a
|
||||
truthy value in the callback.
|
||||
|
||||
## 2016-07-29, Version 0.7.5
|
||||
|
||||
#### API changes:
|
||||
|
||||
- New permission `General.EXTERNAL_EMOTES`.
|
||||
|
||||
#### New:
|
||||
|
||||
- Preemptive rate limit handling: bots can now send messages as fast
|
||||
as they are allowed;
|
||||
- Collection lengths are now printed when inspected with `console.log`:
|
||||
ex. `IGuildCollection { length: 8 }`;
|
||||
- `IDirectMessageChannel` now supports fetching pinned messages.
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Fixed rare case of voice states not syncing after gateway being `RESUMED`;
|
||||
- Fixed some promises returning strings instead of proper `Error` objects;
|
||||
- Fixed array collections crashing on latest V8 engine.
|
||||
|
||||
#### Other:
|
||||
|
||||
- Buffers are now allocated using `Buffer.alloc`/`Buffer.from` instead of
|
||||
deprecated `Buffer` constructor whenever possible.
|
||||
|
||||
## 2016-07-16, Version 0.7.3
|
||||
|
||||
#### API changes:
|
||||
|
||||
- Removed human readable invites.
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Order of pinned messages now matches the client;
|
||||
- Upgraded `ws` dependency from v0.8.0 to v1.1.1, fixes crash on node v6.x.x;
|
||||
- Property `previousNick` in `GUILD_MEMBER_UPDATE` is now set correctly.
|
||||
|
||||
#### Other:
|
||||
|
||||
- Changed permission (methods `IUser/IGuildMember.permissionsFor/can`)
|
||||
error message from `"Invalid user"` to
|
||||
`"User is not a member of the context"`.
|
||||
|
||||
## 2016-06-25, Version 0.7.2
|
||||
|
||||
#### New:
|
||||
|
||||
- Event `GUILD_MEMBER_UPDATE` now exposes object changes:
|
||||
|
||||
- **{Array\<IRole>}** `rolesAdded`;
|
||||
- **{Array\<IRole>}** `rolesRemoved`;
|
||||
- **{String|null}** `previousNick`.
|
||||
|
||||
- `IAuthenticatedUser.setGame/setStatus` now also accept games as strings;
|
||||
|
||||
- Message pinning support:
|
||||
|
||||
- ITextChannel
|
||||
- **{Array\<IMessage>}** `ITextChannel.pinnedMessages`;
|
||||
- **{Promise\<Object, Error>}** `ITextChannel.fetchPinned()`;
|
||||
|
||||
- IMessage
|
||||
- **{Boolean}** `IMessage.pinned`;
|
||||
- **{Promise\<IMessage, Error>}** `IMessage.pin()`;
|
||||
- **{Promise\<IMessage, Error>}** `IMessage.unpin()`;
|
||||
|
||||
- IMessageCollection
|
||||
- **{Array\<IMessage>}** `IMessageCollection.forChannelPinned(channel)` (same as `pinnedMessages`);
|
||||
- **{Promise}** `IMessageCollection.pinMessage(messageId, channelId)`;
|
||||
- **{Promise}** `IMessageCollection.unpinMessage(messageId, channelId)`;
|
||||
- **{void}** `IMessageCollection.purgeChannelPinned(channel)`;
|
||||
- **{void}** `IMessageCollection.purgePinned()`.
|
||||
|
||||
## 2016-06-18, Version 0.7.0
|
||||
|
||||
#### New:
|
||||
|
||||
- Gateway V5 support;
|
||||
- Event `MESSAGE_DELETE_BULK`;
|
||||
- Integrated API (REST) error messages;
|
||||
(ex. `Error: Bad Request (Cannot send an empty message)`);
|
||||
- MFA fields: `IAuthenticatedUser.mfa_enabled`, `IGuild.mfa_level`;
|
||||
- Automatic `Bad Gateway` (HTTP 502) handling, will only throw a 502 after
|
||||
10 retries.
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Permission overwrites for voice channels now actually have `Voice` section.
|
||||
|
||||
## 2016-05-29, Version 0.6.5
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Workaround for `FFmpegEncoder` 'end' event not firing on
|
||||
nodejs v5.11.0/4.4.5+.
|
||||
|
||||
## 2016-05-23, Version 0.6.4
|
||||
|
||||
#### New:
|
||||
|
||||
- User limits in voice channels:
|
||||
|
||||
- Added param `userLimit` to `IChannel.update`;
|
||||
- Channel property `user_limit`;
|
||||
- Method `channel.join()` will return rejected promise if channel is full
|
||||
and permission `Voice.MOVE_MEMBERS` is denied.
|
||||
|
||||
## 2016-05-14, Version 0.6.2
|
||||
|
||||
#### New:
|
||||
|
||||
- Auto-reconnect with a constructor option:
|
||||
`new Discordie({autoReconnect: true});`;
|
||||
- Profile editing aliases `IAuthenticatedUser.setAvatar/setUsername`.
|
||||
|
||||
## 2016-05-10, Version 0.6.1
|
||||
|
||||
#### Discord API Changes:
|
||||
|
||||
- [New `MANAGE_ROLES` (`ADMINISTRATOR`) permission](https://github.com/hammerandchisel/discord-api-docs/issues/41).
|
||||
|
||||
#### New:
|
||||
|
||||
- Bulk-delete messages with `IMessageCollection.deleteMessages(array)`;
|
||||
- Channel cloning `IChannel.clone(name, type, bitrate)`;
|
||||
- Added params `permissionOverwrites`, `bitrate` to `IGuild.createChannel`.
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Fixed self nicknames not setting without `MANAGE_NICKNAMES` permission.
|
||||
|
||||
## 2016-05-04, Version 0.6.0
|
||||
|
||||
#### New:
|
||||
|
||||
- Method `IMessage.resolveContent()` resolving `<@(#|!|&)?id>` entities to
|
||||
names to get human readable content;
|
||||
- Nickname support:
|
||||
- Permissions `CHANGE_NICKNAME`, `MANAGE_NICKNAMES`;
|
||||
- `IGuildMember.nick` property;
|
||||
- `IGuildMember.name` getter, returns nick if exists, otherwise username;
|
||||
- `IGuildMember.setNickname(nick)` method.
|
||||
- Mentionable roles:
|
||||
- `IMessage.mention_roles` property;
|
||||
- Param `mentionable` in `IRole.commit(name, color, hoist, mentionable)`.
|
||||
- Mentions:
|
||||
- `IUser/IGuildMember.nickMention` getter;
|
||||
- `ITextChannel.mention` getter;
|
||||
- `IRole.mention` getter.
|
||||
|
||||
## 2016-04-28, Version 0.5.7
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- FFmpeg processes will be killed with `SIGKILL` if not exited within
|
||||
5 second timeout;
|
||||
- Method `uploadFile` now checks file existence if called with a file path.
|
||||
|
||||
## 2016-04-25, Version 0.5.6
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- `READY` timeout no longer fires after a disconnect.
|
||||
|
||||
#### Performance:
|
||||
|
||||
- Internal opus now starts faster.
|
||||
|
||||
## 2016-04-19, Version 0.5.5
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- FFmpegEncoder stdin errors can now be handled with the standard
|
||||
`encoder.stdin.on("error", handler)`;
|
||||
- Fixed debug mode FFmpegEncoder listener leak warnings from EventEmitter.
|
||||
|
||||
#### Performance:
|
||||
|
||||
- Optimized voice state tracking;
|
||||
- Optimized `(DirectMessage)ChannelCollection.get`;
|
||||
- Events `PRESENCE_UPDATE` and `TYPING_START` will only fire if there are
|
||||
listeners assigned to them.
|
||||
|
||||
## 2016-04-17, Version 0.5.4
|
||||
|
||||
#### New:
|
||||
|
||||
- Gateway sharding support (`shardId` and `shardCount` options in
|
||||
`Discordie` constructor).
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Fixed empty audio output with 48kHz input data.
|
||||
|
||||
## 2016-04-14, Version 0.5.2
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Fixed audio subsystem breaking (not buffering data) when using
|
||||
[PM2](http://pm2.keymetrics.io/) (process manager);
|
||||
|
||||
## 2016-04-13, Version 0.5.1
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Rate limited file uploads with streams now resend data correctly;
|
||||
|
||||
#### Performance:
|
||||
|
||||
- Minor performance improvement for audio mixing without volume set.
|
||||
|
||||
## 2016-04-12, Version 0.5.0
|
||||
|
||||
#### New:
|
||||
|
||||
- High level audio streams (`AudioEncoderStream`, `FFmpegEncoder`,
|
||||
`OggOpusPlayer`, `WebmOpusPlayer`),
|
||||
instantiated using `IVoiceConnection.createExternalEncoder`
|
||||
and `IVoiceConnection.getEncoderStream`.
|
||||
|
||||
## 2016-04-09, Version 0.4.4
|
||||
|
||||
#### New:
|
||||
|
||||
- Rate limit handling for messages. All messages are now put in a queue
|
||||
and sent sequentially;
|
||||
- Low level audio API extensions (`AudioEncoder`) -
|
||||
new methods `.enqueueMultiple` and `.clearQueue`;
|
||||
- Event `GUILD_CREATE` now has a parameter `becameAvailable` to
|
||||
discriminate between joined and unavailable guilds.
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Normal precision scheduling now processes packet queue correctly;
|
||||
- AudioEncoder queue changed to pause after 1 second of inactivity;
|
||||
- V4 READY timeout changed to reset after each `GUILD_CREATE`;
|
||||
- Fixed voice disconnecting after resuming gateway connection;
|
||||
|
||||
## 2016-04-06, Version 0.4.2
|
||||
|
||||
#### New:
|
||||
|
||||
- Gateway V4 support;
|
||||
- Exposed `GATEWAY_RESUMED` event;
|
||||
- Bans now can be added without member object - `IGuild.ban(user)`.
|
||||
|
||||
## 2016-03-25, Version 0.4.0
|
||||
|
||||
#### Notable changes:
|
||||
|
||||
- Fully migrated to bot multiserver voice API (user accounts no longer can
|
||||
connect to more than one guild concurrently);
|
||||
- Improved voice disconnect handling logic: more info in `VOICE_DISCONNECTED`
|
||||
event docs (no breaking changes);
|
||||
- Presence updates for friend lists are no longer dispatched over
|
||||
`PRESENCE_UPDATE` event;
|
||||
- *(Discord-side)* `Invites.accept` no longer works on bot accounts.
|
||||
|
||||
#### New:
|
||||
|
||||
- Exposed `user.bot` boolean property;
|
||||
- Implemented offline guild members requesting:
|
||||
`Users.fetchMembers(singleGuildOrGuildsArray)`;
|
||||
- Alternative methods for deleting/editing messages by id:
|
||||
- `Messages.editMessage(content, messageId, channelId)`;
|
||||
- `Messages.deleteMessage(messageId, channelId)`;
|
||||
- Pending voice connections can now be cancelled with `.leave()` on the same
|
||||
channel.
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- `GUILD_MEMBER_REMOVE` is now handled correctly and actually removes
|
||||
members from cache;
|
||||
- Fixed `IGuild.getPruneEstimate()` and `IGuild.pruneMembers()`;
|
||||
- Encoder states are no longer created in proxy mode;
|
||||
- Voice connections now properly disconnect on `GUILD_UNAVAILABLE`;
|
||||
- Fixed `IVoiceChannel.joined` reporting incorrect state for pending
|
||||
connections.
|
||||
|
||||
#### Performance:
|
||||
|
||||
- Improved performance for voice encryption and RTP muxing.
|
||||
|
||||
## 2016-03-09, Version 0.3.0
|
||||
|
||||
#### Notable changes:
|
||||
|
||||
- Memory and CPU usage has been reduced greatly;
|
||||
- Implemented caching of member interfaces;
|
||||
- Messages are sorted on insertion using binary sort, sorting after fetching
|
||||
is removed;
|
||||
- `JSON.stringify` on interfaces returns a copy of raw model data instead
|
||||
of stringifying models recursively;
|
||||
- Interfaces can now be properly formatted (inspected) using `console.log`
|
||||
and `util.inspect`;
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Fix voice state tracking on `READY` for clients in multiple servers;
|
||||
- Cache voice server address on connect and no longer attempt to resolve
|
||||
hostname during UDP packet send calls;
|
||||
- Fix `DirectMessageChannels.getOrOpen(recipient)` crashing on node 5.7.0;
|
||||
|
||||
|
||||
## 2016-02-27, Version 0.2.1
|
||||
|
||||
#### Performance:
|
||||
|
||||
- Improve performance of `<Collection>.get`;
|
||||
|
||||
#### Fixes:
|
||||
|
||||
- Fix voice leave or disconnect crashing the library when called for voice
|
||||
connections on secondary gateways;
|
25
node_modules/discordie/deps/cas/addtrustexternalcaroot.crt
generated
vendored
Normal file
25
node_modules/discordie/deps/cas/addtrustexternalcaroot.crt
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
|
||||
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
|
||||
IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
|
||||
MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
|
||||
FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
|
||||
bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
|
||||
dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
|
||||
H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
|
||||
uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
|
||||
mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
|
||||
a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
|
||||
E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
|
||||
WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
|
||||
VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
|
||||
Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
|
||||
cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
|
||||
IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
|
||||
AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
|
||||
YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
|
||||
6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
|
||||
Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
|
||||
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
|
||||
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
|
||||
-----END CERTIFICATE-----
|
32
node_modules/discordie/deps/cas/comodorsaaddtrustca.crt
generated
vendored
Normal file
32
node_modules/discordie/deps/cas/comodorsaaddtrustca.crt
generated
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIFdDCCBFygAwIBAgIQJ2buVutJ846r13Ci/ITeIjANBgkqhkiG9w0BAQwFADBv
|
||||
MQswCQYDVQQGEwJTRTEUMBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFk
|
||||
ZFRydXN0IEV4dGVybmFsIFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBF
|
||||
eHRlcm5hbCBDQSBSb290MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFow
|
||||
gYUxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVhdGVyIE1hbmNoZXN0ZXIxEDAO
|
||||
BgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9ETyBDQSBMaW1pdGVkMSswKQYD
|
||||
VQQDEyJDT01PRE8gUlNBIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkq
|
||||
hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAkehUktIKVrGsDSTdxc9EZ3SZKzejfSNw
|
||||
AHG8U9/E+ioSj0t/EFa9n3Byt2F/yUsPF6c947AEYe7/EZfH9IY+Cvo+XPmT5jR6
|
||||
2RRr55yzhaCCenavcZDX7P0N+pxs+t+wgvQUfvm+xKYvT3+Zf7X8Z0NyvQwA1onr
|
||||
ayzT7Y+YHBSrfuXjbvzYqOSSJNpDa2K4Vf3qwbxstovzDo2a5JtsaZn4eEgwRdWt
|
||||
4Q08RWD8MpZRJ7xnw8outmvqRsfHIKCxH2XeSAi6pE6p8oNGN4Tr6MyBSENnTnIq
|
||||
m1y9TBsoilwie7SrmNnu4FGDwwlGTm0+mfqVF9p8M1dBPI1R7Qu2XK8sYxrfV8g/
|
||||
vOldxJuvRZnio1oktLqpVj3Pb6r/SVi+8Kj/9Lit6Tf7urj0Czr56ENCHonYhMsT
|
||||
8dm74YlguIwoVqwUHZwK53Hrzw7dPamWoUi9PPevtQ0iTMARgexWO/bTouJbt7IE
|
||||
IlKVgJNp6I5MZfGRAy1wdALqi2cVKWlSArvX31BqVUa/oKMoYX9w0MOiqiwhqkfO
|
||||
KJwGRXa/ghgntNWutMtQ5mv0TIZxMOmm3xaG4Nj/QN370EKIf6MzOi5cHkERgWPO
|
||||
GHFrK+ymircxXDpqR+DDeVnWIBqv8mqYqnK8V0rSS527EPywTEHl7R09XiidnMy/
|
||||
s1Hap0flhFMCAwEAAaOB9DCB8TAfBgNVHSMEGDAWgBStvZh6NLQm9/rEJlTvA73g
|
||||
JMtUGjAdBgNVHQ4EFgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQD
|
||||
AgGGMA8GA1UdEwEB/wQFMAMBAf8wEQYDVR0gBAowCDAGBgRVHSAAMEQGA1UdHwQ9
|
||||
MDswOaA3oDWGM2h0dHA6Ly9jcmwudXNlcnRydXN0LmNvbS9BZGRUcnVzdEV4dGVy
|
||||
bmFsQ0FSb290LmNybDA1BggrBgEFBQcBAQQpMCcwJQYIKwYBBQUHMAGGGWh0dHA6
|
||||
Ly9vY3NwLnVzZXJ0cnVzdC5jb20wDQYJKoZIhvcNAQEMBQADggEBAGS/g/FfmoXQ
|
||||
zbihKVcN6Fr30ek+8nYEbvFScLsePP9NDXRqzIGCJdPDoCpdTPW6i6FtxFQJdcfj
|
||||
Jw5dhHk3QBN39bSsHNA7qxcS1u80GH4r6XnTq1dFDK8o+tDb5VCViLvfhVdpfZLY
|
||||
Uspzgb8c8+a4bmYRBbMelC1/kZWSWfFMzqORcUx8Rww7Cxn2obFshj5cqsQugsv5
|
||||
B5a6SE2Q8pTIqXOi6wZ7I53eovNNVZ96YUWYGGjHXkBrI/V5eu+MtWuLt29G9Hvx
|
||||
PUsE2JOAWVrgQSQdso8VYFhH2+9uRv0V9dlfmrPb2LjkQLPNlzmuhbsdjrzch5vR
|
||||
pu/xO28QOG8=
|
||||
-----END CERTIFICATE-----
|
35
node_modules/discordie/deps/cas/comodorsadomainvalidationsecureserverca.crt
generated
vendored
Normal file
35
node_modules/discordie/deps/cas/comodorsadomainvalidationsecureserverca.crt
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIGCDCCA/CgAwIBAgIQKy5u6tl1NmwUim7bo3yMBzANBgkqhkiG9w0BAQwFADCB
|
||||
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
|
||||
A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
|
||||
BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTQwMjEy
|
||||
MDAwMDAwWhcNMjkwMjExMjM1OTU5WjCBkDELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
|
||||
EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
|
||||
Q09NT0RPIENBIExpbWl0ZWQxNjA0BgNVBAMTLUNPTU9ETyBSU0EgRG9tYWluIFZh
|
||||
bGlkYXRpb24gU2VjdXJlIFNlcnZlciBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
||||
ADCCAQoCggEBAI7CAhnhoFmk6zg1jSz9AdDTScBkxwtiBUUWOqigwAwCfx3M28Sh
|
||||
bXcDow+G+eMGnD4LgYqbSRutA776S9uMIO3Vzl5ljj4Nr0zCsLdFXlIvNN5IJGS0
|
||||
Qa4Al/e+Z96e0HqnU4A7fK31llVvl0cKfIWLIpeNs4TgllfQcBhglo/uLQeTnaG6
|
||||
ytHNe+nEKpooIZFNb5JPJaXyejXdJtxGpdCsWTWM/06RQ1A/WZMebFEh7lgUq/51
|
||||
UHg+TLAchhP6a5i84DuUHoVS3AOTJBhuyydRReZw3iVDpA3hSqXttn7IzW3uLh0n
|
||||
c13cRTCAquOyQQuvvUSH2rnlG51/ruWFgqUCAwEAAaOCAWUwggFhMB8GA1UdIwQY
|
||||
MBaAFLuvfgI9+qbxPISOre44mOzZMjLUMB0GA1UdDgQWBBSQr2o6lFoL2JDqElZz
|
||||
30O0Oija5zAOBgNVHQ8BAf8EBAMCAYYwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV
|
||||
HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwGwYDVR0gBBQwEjAGBgRVHSAAMAgG
|
||||
BmeBDAECATBMBgNVHR8ERTBDMEGgP6A9hjtodHRwOi8vY3JsLmNvbW9kb2NhLmNv
|
||||
bS9DT01PRE9SU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBxBggrBgEFBQcB
|
||||
AQRlMGMwOwYIKwYBBQUHMAKGL2h0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NPTU9E
|
||||
T1JTQUFkZFRydXN0Q0EuY3J0MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5jb21v
|
||||
ZG9jYS5jb20wDQYJKoZIhvcNAQEMBQADggIBAE4rdk+SHGI2ibp3wScF9BzWRJ2p
|
||||
mj6q1WZmAT7qSeaiNbz69t2Vjpk1mA42GHWx3d1Qcnyu3HeIzg/3kCDKo2cuH1Z/
|
||||
e+FE6kKVxF0NAVBGFfKBiVlsit2M8RKhjTpCipj4SzR7JzsItG8kO3KdY3RYPBps
|
||||
P0/HEZrIqPW1N+8QRcZs2eBelSaz662jue5/DJpmNXMyYE7l3YphLG5SEXdoltMY
|
||||
dVEVABt0iN3hxzgEQyjpFv3ZBdRdRydg1vs4O2xyopT4Qhrf7W8GjEXCBgCq5Ojc
|
||||
2bXhc3js9iPc0d1sjhqPpepUfJa3w/5Vjo1JXvxku88+vZbrac2/4EjxYoIQ5QxG
|
||||
V/Iz2tDIY+3GH5QFlkoakdH368+PUq4NCNk+qKBR6cGHdNXJ93SrLlP7u3r7l+L4
|
||||
HyaPs9Kg4DdbKDsx5Q5XLVq4rXmsXiBmGqW5prU5wfWYQ//u+aen/e7KJD2AFsQX
|
||||
j4rBYKEMrltDR5FL1ZoXX/nUh8HCjLfn4g8wGTeGrODcQgPmlKidrv0PJFGUzpII
|
||||
0fxQ8ANAe4hZ7Q7drNJ3gjTcBpUC2JD5Leo31Rpg0Gcg19hCC0Wvgmje3WYkN5Ap
|
||||
lBlGGSW4gNfL1IYoakRwJiNiqZ+Gb7+6kHDSVneFeO/qJakXzlByjAA6quPbYzSf
|
||||
+AZxAeKCINT+b72x
|
||||
-----END CERTIFICATE-----
|
14
node_modules/discordie/deps/nopus/index.js
generated
vendored
Normal file
14
node_modules/discordie/deps/nopus/index.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
var ex = "uncaughtException";
|
||||
var pl = process.listeners(ex);
|
||||
|
||||
var opus = require("./opus-js/opus");
|
||||
var resampler = require("./opus-js/resampler");
|
||||
|
||||
process.removeAllListeners(ex);
|
||||
for (var i = 0; i < pl.length; i++) process.on(ex, pl[i]);
|
||||
|
||||
module.exports.Opus = opus.Opus;
|
||||
module.exports.OpusApplication = opus.OpusApplication;
|
||||
module.exports.OpusEncoder = opus.OpusEncoder;
|
||||
module.exports.OpusDecoder = opus.OpusDecoder;
|
||||
module.exports.Resampler = resampler.SpeexResampler;
|
28
node_modules/discordie/deps/nopus/opus-js/copying.libopus
generated
vendored
Normal file
28
node_modules/discordie/deps/nopus/opus-js/copying.libopus
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
Copyright (c) 1994-2013 Xiph.Org Foundation and contributors
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Xiph.Org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION
|
||||
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
35
node_modules/discordie/deps/nopus/opus-js/copying.libspeex
generated
vendored
Normal file
35
node_modules/discordie/deps/nopus/opus-js/copying.libspeex
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
Copyright 2002-2008 Xiph.org Foundation
|
||||
Copyright 2002-2008 Jean-Marc Valin
|
||||
Copyright 2005-2007 Analog Devices Inc.
|
||||
Copyright 2005-2008 Commonwealth Scientific and Industrial Research
|
||||
Organisation (CSIRO)
|
||||
Copyright 1993, 2002, 2006 David Rowe
|
||||
Copyright 2003 EpicGames
|
||||
Copyright 1992-1994 Jutta Degener, Carsten Bormann
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
- Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
- Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
- Neither the name of the Xiph.org Foundation nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
29
node_modules/discordie/deps/nopus/opus-js/copying.wrapper
generated
vendored
Normal file
29
node_modules/discordie/deps/nopus/opus-js/copying.wrapper
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
Copyright (c) 2013-2014, Kazuki Oikawa
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
node_modules/discordie/deps/nopus/opus-js/libopus_libspeexdsp.js
generated
vendored
Normal file
31
node_modules/discordie/deps/nopus/opus-js/libopus_libspeexdsp.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
217
node_modules/discordie/deps/nopus/opus-js/opus.js
generated
vendored
Normal file
217
node_modules/discordie/deps/nopus/opus-js/opus.js
generated
vendored
Normal file
@ -0,0 +1,217 @@
|
||||
///<reference path="d.ts/asm.d.ts" />
|
||||
///<reference path="d.ts/libopus.d.ts" />
|
||||
|
||||
var native = require("./libopus_libspeexdsp");
|
||||
|
||||
var OPUS_SET_BITRATE_REQUEST = 4002;
|
||||
|
||||
var OpusApplication;
|
||||
(function (OpusApplication) {
|
||||
OpusApplication[OpusApplication["VoIP"] = 2048] = "VoIP";
|
||||
OpusApplication[OpusApplication["Audio"] = 2049] = "Audio";
|
||||
OpusApplication[OpusApplication["RestrictedLowDelay"] = 2051] = "RestrictedLowDelay";
|
||||
})(OpusApplication || (OpusApplication = {}));
|
||||
var OpusError;
|
||||
(function (OpusError) {
|
||||
OpusError[OpusError["OK"] = 0] = "OK";
|
||||
OpusError[OpusError["BadArgument"] = -1] = "BadArgument";
|
||||
OpusError[OpusError["BufferTooSmall"] = -2] = "BufferTooSmall";
|
||||
OpusError[OpusError["InternalError"] = -3] = "InternalError";
|
||||
OpusError[OpusError["InvalidPacket"] = -4] = "InvalidPacket";
|
||||
OpusError[OpusError["Unimplemented"] = -5] = "Unimplemented";
|
||||
OpusError[OpusError["InvalidState"] = -6] = "InvalidState";
|
||||
OpusError[OpusError["AllocFail"] = -7] = "AllocFail";
|
||||
})(OpusError || (OpusError = {}));
|
||||
var Opus = (function () {
|
||||
function Opus() {
|
||||
}
|
||||
Opus.getVersion = function () {
|
||||
var ptr = native._opus_get_version_string();
|
||||
return Pointer_stringify(ptr);
|
||||
};
|
||||
Opus.getMaxFrameSize = function (numberOfStreams) {
|
||||
if (numberOfStreams === void 0) { numberOfStreams = 1; }
|
||||
return (1275 * 3 + 7) * numberOfStreams;
|
||||
};
|
||||
Opus.getMinFrameDuration = function () {
|
||||
return 2.5;
|
||||
};
|
||||
Opus.getMaxFrameDuration = function () {
|
||||
return 60;
|
||||
};
|
||||
Opus.validFrameDuration = function (x) {
|
||||
return [2.5, 5, 10, 20, 40, 60].some(function (element) {
|
||||
return element == x;
|
||||
});
|
||||
};
|
||||
Opus.getMaxSamplesPerChannel = function (sampling_rate) {
|
||||
return sampling_rate / 1000 * Opus.getMaxFrameDuration();
|
||||
};
|
||||
return Opus;
|
||||
})();
|
||||
var OpusEncoder = (function () {
|
||||
function OpusEncoder(sampling_rate, channels, app, frame_duration) {
|
||||
if (frame_duration === void 0) { frame_duration = 20; }
|
||||
this.handle = 0;
|
||||
this.frame_size = 0;
|
||||
this.in_ptr = 0;
|
||||
this.in_off = 0;
|
||||
this.out_ptr = 0;
|
||||
if (!Opus.validFrameDuration(frame_duration))
|
||||
throw 'invalid frame duration';
|
||||
this.frame_size = sampling_rate * frame_duration / 1000;
|
||||
var err_ptr = native.allocate(4, 'i32', native.ALLOC_STACK);
|
||||
this.handle = native._opus_encoder_create(sampling_rate, channels, app, err_ptr);
|
||||
if (native.getValue(err_ptr, 'i32') != 0 /* OK */)
|
||||
throw 'opus_encoder_create failed: ' + native.getValue(err_ptr, 'i32');
|
||||
this.in_ptr = native._malloc(this.frame_size * channels * 4);
|
||||
this.in_len = this.frame_size * channels;
|
||||
this.in_i16 = native.HEAP16.subarray(this.in_ptr >> 1, (this.in_ptr >> 1) + this.in_len);
|
||||
this.in_f32 = native.HEAPF32.subarray(this.in_ptr >> 2, (this.in_ptr >> 2) + this.in_len);
|
||||
this.out_bytes = Opus.getMaxFrameSize();
|
||||
this.out_ptr = native._malloc(this.out_bytes);
|
||||
this.out_buf = native.HEAPU8.subarray(this.out_ptr, this.out_ptr + this.out_bytes);
|
||||
}
|
||||
OpusEncoder.prototype.set_bitrate = function (bitrate) {
|
||||
var bitrate_ptr = native.allocate(4, 'i32', native.ALLOC_STACK);
|
||||
native.setValue(bitrate_ptr, bitrate, 'i32');
|
||||
var ret = native._opus_encoder_ctl(this.handle, OPUS_SET_BITRATE_REQUEST, bitrate_ptr);
|
||||
if (ret < 0)
|
||||
throw 'opus_encoder_ctl failed: ' + ret;
|
||||
};
|
||||
OpusEncoder.prototype.encode = function (pcm) {
|
||||
var output = [];
|
||||
var pcm_off = 0;
|
||||
while (pcm.length - pcm_off >= this.in_len - this.in_off) {
|
||||
if (this.in_off > 0) {
|
||||
this.in_i16.set(pcm.subarray(pcm_off, pcm_off + this.in_len - this.in_off), this.in_off);
|
||||
pcm_off += this.in_len - this.in_off;
|
||||
this.in_off = 0;
|
||||
}
|
||||
else {
|
||||
this.in_i16.set(pcm.subarray(pcm_off, pcm_off + this.in_len));
|
||||
pcm_off += this.in_len;
|
||||
}
|
||||
var ret = native._opus_encode(this.handle, this.in_ptr, this.frame_size, this.out_ptr, this.out_bytes);
|
||||
if (ret <= 0)
|
||||
throw 'opus_encode failed: ' + ret;
|
||||
var packet = new ArrayBuffer(ret);
|
||||
new Uint8Array(packet).set(this.out_buf.subarray(0, ret));
|
||||
output.push(packet);
|
||||
}
|
||||
if (pcm_off < pcm.length) {
|
||||
this.in_i16.set(pcm.subarray(pcm_off));
|
||||
this.in_off = pcm.length - pcm_off;
|
||||
}
|
||||
return output;
|
||||
};
|
||||
OpusEncoder.prototype.encode_float = function (pcm) {
|
||||
var output = [];
|
||||
var pcm_off = 0;
|
||||
while (pcm.length - pcm_off >= this.in_len - this.in_off) {
|
||||
if (this.in_off > 0) {
|
||||
this.in_f32.set(pcm.subarray(pcm_off, pcm_off + this.in_len - this.in_off), this.in_off);
|
||||
pcm_off += this.in_len - this.in_off;
|
||||
this.in_off = 0;
|
||||
}
|
||||
else {
|
||||
this.in_f32.set(pcm.subarray(pcm_off, pcm_off + this.in_len));
|
||||
pcm_off += this.in_len;
|
||||
}
|
||||
var ret = native._opus_encode_float(this.handle, this.in_ptr, this.frame_size, this.out_ptr, this.out_bytes);
|
||||
if (ret <= 0)
|
||||
throw 'opus_encode failed: ' + ret;
|
||||
var packet = new ArrayBuffer(ret);
|
||||
new Uint8Array(packet).set(this.out_buf.subarray(0, ret));
|
||||
output.push(packet);
|
||||
}
|
||||
if (pcm_off < pcm.length) {
|
||||
this.in_f32.set(pcm.subarray(pcm_off));
|
||||
this.in_off = pcm.length - pcm_off;
|
||||
}
|
||||
return output;
|
||||
};
|
||||
OpusEncoder.prototype.encode_final = function () {
|
||||
if (this.in_off == 0)
|
||||
return new ArrayBuffer(0);
|
||||
for (var i = this.in_off; i < this.in_len; ++i)
|
||||
this.in_i16[i] = 0;
|
||||
var ret = native._opus_encode(this.handle, this.in_ptr, this.frame_size, this.out_ptr, this.out_bytes);
|
||||
if (ret <= 0)
|
||||
throw 'opus_encode failed: ' + ret;
|
||||
var packet = new ArrayBuffer(ret);
|
||||
new Uint8Array(packet).set(this.out_buf.subarray(0, ret));
|
||||
return packet;
|
||||
};
|
||||
OpusEncoder.prototype.encode_float_final = function () {
|
||||
if (this.in_off == 0)
|
||||
return new ArrayBuffer(0);
|
||||
for (var i = this.in_off; i < this.in_len; ++i)
|
||||
this.in_f32[i] = 0;
|
||||
var ret = native._opus_encode_float(this.handle, this.in_ptr, this.frame_size, this.out_ptr, this.out_bytes);
|
||||
if (ret <= 0)
|
||||
throw 'opus_encode failed: ' + ret;
|
||||
var packet = new ArrayBuffer(ret);
|
||||
new Uint8Array(packet).set(this.out_buf.subarray(0, ret));
|
||||
return packet;
|
||||
};
|
||||
OpusEncoder.prototype.destroy = function () {
|
||||
if (!this.handle)
|
||||
return;
|
||||
native._opus_encoder_destroy(this.handle);
|
||||
native._free(this.in_ptr);
|
||||
this.handle = this.in_ptr = 0;
|
||||
};
|
||||
return OpusEncoder;
|
||||
})();
|
||||
var OpusDecoder = (function () {
|
||||
function OpusDecoder(sampling_rate, channels) {
|
||||
this.handle = 0;
|
||||
this.in_ptr = 0;
|
||||
this.out_ptr = 0;
|
||||
this.channels = channels;
|
||||
var err_ptr = native.allocate(4, 'i32', native.ALLOC_STACK);
|
||||
this.handle = native._opus_decoder_create(sampling_rate, channels, err_ptr);
|
||||
if (native.getValue(err_ptr, 'i32') != 0 /* OK */)
|
||||
throw 'opus_decoder_create failed: ' + native.getValue(err_ptr, 'i32');
|
||||
this.in_ptr = native._malloc(Opus.getMaxFrameSize(channels));
|
||||
this.in_buf = native.HEAPU8.subarray(this.in_ptr, this.in_ptr + Opus.getMaxFrameSize(channels));
|
||||
this.out_len = Opus.getMaxSamplesPerChannel(sampling_rate);
|
||||
var out_bytes = this.out_len * channels * 4;
|
||||
this.out_ptr = native._malloc(out_bytes);
|
||||
this.out_i16 = native.HEAP16.subarray(this.out_ptr >> 1, (this.out_ptr + out_bytes) >> 1);
|
||||
this.out_f32 = native.HEAPF32.subarray(this.out_ptr >> 2, (this.out_ptr + out_bytes) >> 2);
|
||||
}
|
||||
OpusDecoder.prototype.decode = function (packet) {
|
||||
this.in_buf.set(new Uint8Array(packet));
|
||||
var ret = native._opus_decode(this.handle, this.in_ptr, packet.byteLength, this.out_ptr, this.out_len, 0);
|
||||
if (ret < 0)
|
||||
throw 'opus_decode failed: ' + ret;
|
||||
var samples = new Int16Array(ret * this.channels);
|
||||
samples.set(this.out_i16.subarray(0, samples.length));
|
||||
return samples;
|
||||
};
|
||||
OpusDecoder.prototype.decode_float = function (packet) {
|
||||
this.in_buf.set(new Uint8Array(packet));
|
||||
var ret = native._opus_decode_float(this.handle, this.in_ptr, packet.byteLength, this.out_ptr, this.out_len, 0);
|
||||
if (ret < 0)
|
||||
throw 'opus_decode failed: ' + ret;
|
||||
var samples = new Float32Array(ret * this.channels);
|
||||
samples.set(this.out_f32.subarray(0, samples.length));
|
||||
return samples;
|
||||
};
|
||||
OpusDecoder.prototype.destroy = function () {
|
||||
if (!this.handle)
|
||||
return;
|
||||
native._opus_decoder_destroy(this.handle);
|
||||
native._free(this.in_ptr);
|
||||
native._free(this.out_ptr);
|
||||
this.handle = this.in_ptr = this.out_ptr = 0;
|
||||
};
|
||||
return OpusDecoder;
|
||||
})();
|
||||
|
||||
module.exports.Opus = Opus;
|
||||
module.exports.OpusApplication = OpusApplication;
|
||||
module.exports.OpusEncoder = OpusEncoder;
|
||||
module.exports.OpusDecoder = OpusDecoder;
|
152
node_modules/discordie/deps/nopus/opus-js/resampler.js
generated
vendored
Normal file
152
node_modules/discordie/deps/nopus/opus-js/resampler.js
generated
vendored
Normal file
@ -0,0 +1,152 @@
|
||||
///<reference path="d.ts/asm.d.ts" />
|
||||
///<reference path="d.ts/libspeexdsp.d.ts" />
|
||||
|
||||
var native = require("./libopus_libspeexdsp");
|
||||
|
||||
var SpeexResampler = (function () {
|
||||
function SpeexResampler(channels, in_rate, out_rate, bits_per_sample, is_float, quality) {
|
||||
if (quality === void 0) { quality = 5; }
|
||||
this.handle = 0;
|
||||
this.in_ptr = 0;
|
||||
this.out_ptr = 0;
|
||||
this.in_capacity = 0;
|
||||
this.in_len_ptr = 0;
|
||||
this.out_len_ptr = 0;
|
||||
this.channels = channels;
|
||||
this.in_rate = in_rate;
|
||||
this.out_rate = out_rate;
|
||||
this.bits_per_sample = bits_per_sample;
|
||||
var bytes = bits_per_sample / 8;
|
||||
if (bits_per_sample % 8 != 0 || bytes < 1 || bytes > 4)
|
||||
throw 'argument error: bits_per_sample = ' + bits_per_sample;
|
||||
if (is_float && bits_per_sample != 32)
|
||||
throw 'argument error: if is_float=true, bits_per_sample must be 32';
|
||||
var err_ptr = native.allocate(4, 'i32', native.ALLOC_STACK);
|
||||
this.handle = native._speex_resampler_init(channels, in_rate, out_rate, quality, err_ptr);
|
||||
if (native.getValue(err_ptr, 'i32') != 0)
|
||||
throw 'speex_resampler_init failed: ret=' + native.getValue(err_ptr, 'i32');
|
||||
if (!is_float) {
|
||||
if (bits_per_sample == 8)
|
||||
this.copy_to_buf = this._from_i8;
|
||||
else if (bits_per_sample == 16) {
|
||||
this.copy_to_buf = this._from_i16;
|
||||
}
|
||||
else if (bits_per_sample == 24)
|
||||
this.copy_to_buf = this._from_i24;
|
||||
else if (bits_per_sample == 32)
|
||||
this.copy_to_buf = this._from_i32;
|
||||
}
|
||||
else {
|
||||
this.copy_to_buf = this._from_f32;
|
||||
}
|
||||
this.in_len_ptr = native._malloc(4);
|
||||
this.out_len_ptr = native._malloc(4);
|
||||
}
|
||||
SpeexResampler.prototype.process = function (raw_input) {
|
||||
if (!this.handle)
|
||||
throw 'disposed object';
|
||||
var samples = (raw_input.byteLength / (this.bits_per_sample / 8) / this.channels);
|
||||
var outSamples = Math.ceil(samples * this.out_rate / this.in_rate);
|
||||
var requireSize = samples * 4;
|
||||
if (this.in_capacity < requireSize) {
|
||||
if (this.in_ptr)
|
||||
native._free(this.in_ptr);
|
||||
if (this.out_ptr)
|
||||
native._free(this.out_ptr);
|
||||
this.in_ptr = native._malloc(requireSize);
|
||||
this.out_ptr = native._malloc(outSamples * 4);
|
||||
this.in_capacity = requireSize;
|
||||
}
|
||||
var results = [];
|
||||
for (var ch = 0; ch < this.channels; ++ch) {
|
||||
this.copy_to_buf(raw_input, ch, samples);
|
||||
native.setValue(this.in_len_ptr, samples, 'i32');
|
||||
native.setValue(this.out_len_ptr, outSamples, 'i32');
|
||||
var ret = native._speex_resampler_process_float(this.handle, ch, this.in_ptr, this.in_len_ptr, this.out_ptr, this.out_len_ptr);
|
||||
if (ret != 0)
|
||||
throw 'speex_resampler_process_float failed: ' + ret;
|
||||
var ret_samples = native.getValue(this.out_len_ptr, 'i32');
|
||||
var ary = new Float32Array(ret_samples);
|
||||
ary.set(native.HEAPF32.subarray(this.out_ptr >> 2, (this.out_ptr >> 2) + ret_samples));
|
||||
results.push(ary);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
SpeexResampler.prototype.process_interleaved = function (raw_input) {
|
||||
if (!this.handle)
|
||||
throw 'disposed object';
|
||||
var samples = raw_input.byteLength / (this.bits_per_sample / 8);
|
||||
var outSamples = Math.ceil(samples * this.out_rate / this.in_rate);
|
||||
var requireSize = samples * 4;
|
||||
if (this.in_capacity < requireSize) {
|
||||
if (this.in_ptr)
|
||||
native._free(this.in_ptr);
|
||||
if (this.out_ptr)
|
||||
native._free(this.out_ptr);
|
||||
this.in_ptr = native._malloc(requireSize);
|
||||
this.out_ptr = native._malloc(outSamples * 4);
|
||||
this.in_capacity = requireSize;
|
||||
}
|
||||
this.copy_to_buf(raw_input, -1, samples);
|
||||
native.setValue(this.in_len_ptr, samples / this.channels, 'i32');
|
||||
native.setValue(this.out_len_ptr, outSamples / this.channels, 'i32');
|
||||
var ret = native._speex_resampler_process_interleaved_float(this.handle, this.in_ptr, this.in_len_ptr, this.out_ptr, this.out_len_ptr);
|
||||
if (ret != 0)
|
||||
throw 'speex_resampler_process_interleaved_float failed: ' + ret;
|
||||
var ret_samples = native.getValue(this.out_len_ptr, 'i32') * this.channels;
|
||||
var result = new Float32Array(ret_samples);
|
||||
result.set(native.HEAPF32.subarray(this.out_ptr >> 2, (this.out_ptr >> 2) + ret_samples));
|
||||
return result;
|
||||
};
|
||||
SpeexResampler.prototype.destroy = function () {
|
||||
if (!this.handle)
|
||||
return;
|
||||
native._speex_resampler_destroy(this.handle);
|
||||
this.handle = 0;
|
||||
native._free(this.in_len_ptr);
|
||||
native._free(this.out_len_ptr);
|
||||
if (this.in_ptr)
|
||||
native._free(this.in_ptr);
|
||||
if (this.out_ptr)
|
||||
native._free(this.out_ptr);
|
||||
this.in_len_ptr = this.out_len_ptr = this.in_ptr = this.out_ptr = 0;
|
||||
};
|
||||
SpeexResampler.prototype._from_i8 = function (raw_input, ch, samples) {
|
||||
var input = new Int8Array(raw_input);
|
||||
};
|
||||
SpeexResampler.prototype._from_i16 = function (raw_input, ch, samples) {
|
||||
var input = new Int16Array(raw_input);
|
||||
var off = this.in_ptr >> 2;
|
||||
if (ch >= 0) {
|
||||
var tc = this.channels;
|
||||
for (var i = 0; i < samples; ++i)
|
||||
native.HEAPF32[off + i] = input[i * tc + ch] / 32768.0;
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < samples; ++i)
|
||||
native.HEAPF32[off + i] = input[i] / 32768.0;
|
||||
}
|
||||
};
|
||||
SpeexResampler.prototype._from_i24 = function (raw_input, ch, samples) {
|
||||
var input = new Uint8Array(raw_input);
|
||||
};
|
||||
SpeexResampler.prototype._from_i32 = function (raw_input, ch, samples) {
|
||||
var input = new Int32Array(raw_input);
|
||||
};
|
||||
SpeexResampler.prototype._from_f32 = function (raw_input, ch, samples) {
|
||||
var input = new Float32Array(raw_input);
|
||||
var off = this.in_ptr >> 2;
|
||||
if (ch >= 0) {
|
||||
var tc = this.channels;
|
||||
for (var i = 0; i < samples; ++i)
|
||||
native.HEAPF32[off + i] = input[i * tc + ch];
|
||||
}
|
||||
else {
|
||||
for (var i = 0; i < samples; ++i)
|
||||
native.HEAPF32[off + i] = input[i];
|
||||
}
|
||||
};
|
||||
return SpeexResampler;
|
||||
})();
|
||||
|
||||
module.exports.SpeexResampler = SpeexResampler;
|
194
node_modules/discordie/examples/echo.js
generated
vendored
Normal file
194
node_modules/discordie/examples/echo.js
generated
vendored
Normal file
@ -0,0 +1,194 @@
|
||||
"use strict";
|
||||
|
||||
// voice echo bot
|
||||
|
||||
// records and sends audio using `proxy` mode (without decoding/encoding/saving anything)
|
||||
// variable `var recordTime = 10;` controls duration of recording in seconds
|
||||
|
||||
// commands:
|
||||
// ~!~echo - joins voice channel and records audio, then plays recorded audio back
|
||||
// ~!~stop - stops recording/playing
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var Discordie;
|
||||
try { Discordie = require("../"); } catch(e) {}
|
||||
try { Discordie = require("discordie"); } catch(e) {}
|
||||
|
||||
var client = new Discordie({autoReconnect: true});
|
||||
|
||||
var auth = { token: "<BOT-TOKEN>" };
|
||||
try { auth = require("./auth"); } catch(e) {}
|
||||
|
||||
client.connect(auth);
|
||||
|
||||
var recordTime = 10;
|
||||
var recordTimer = null;
|
||||
|
||||
var recordReply = null;
|
||||
var recordStartTime = null;
|
||||
var recordedData = [];
|
||||
var recordingUser = null;
|
||||
|
||||
client.Dispatcher.on("MESSAGE_CREATE", e => {
|
||||
console.log("new message: ");
|
||||
console.log(JSON.stringify(e.message, null, " "));
|
||||
console.log("e.message.content: " + e.message.content);
|
||||
|
||||
const content = e.message.content;
|
||||
const guild = e.message.channel.guild;
|
||||
|
||||
if (content == "~!~echo") {
|
||||
if (recordingUser)
|
||||
return e.message.reply("Already recording");
|
||||
|
||||
const channelToJoin = e.message.author.getVoiceChannel(guild);
|
||||
if (!channelToJoin)
|
||||
return e.message.reply("Join a voice channel first");
|
||||
|
||||
channelToJoin.join().then(info => {
|
||||
recordReply = e.message.reply.bind(e.message);
|
||||
e.message.reply("Recording audio for " + recordTime + " seconds");
|
||||
recordedData = [];
|
||||
recordingUser = e.message.author.id;
|
||||
recordStartTime = Date.now();
|
||||
|
||||
recordTimer = setTimeout(() => {
|
||||
play(info);
|
||||
e.message.reply("Playing");
|
||||
}, recordTime * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
if (content == "~!~stop") {
|
||||
e.message.reply("Stopped");
|
||||
stopPlaying = true;
|
||||
recordingUser = false;
|
||||
if (recordTimer) {
|
||||
clearTimeout(recordTimer);
|
||||
recordTimer = null;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.Dispatcher.on("VOICE_CONNECTED", e => {
|
||||
e.voiceConnection.getDecoder()
|
||||
.onPacket = (packet) => {
|
||||
const user = e.voiceConnection.ssrcToMember(packet.ssrc);
|
||||
if (!user) return;
|
||||
if (user.id != recordingUser) return;
|
||||
packet.playbackTime = Date.now() - recordStartTime;
|
||||
recordedData.push(packet);
|
||||
|
||||
const name = user ? user.username : "<unknown>";
|
||||
console.log(
|
||||
"recording " + packet.chunk.length +
|
||||
" bytes from " + name +
|
||||
" @ " + packet.timestamp
|
||||
);
|
||||
};
|
||||
// set callback on `.onPacketDecoded` to enable decoding and
|
||||
// have decoded audio in `packet.chunk`
|
||||
});
|
||||
|
||||
var stopPlaying = false;
|
||||
function play(info) {
|
||||
stopPlaying = false;
|
||||
var playbackStartTime = Date.now();
|
||||
|
||||
if (!client.VoiceConnections.length)
|
||||
return console.log("Voice not connected");
|
||||
|
||||
if (!info) info = client.VoiceConnections[0];
|
||||
var voiceConnection = info.voiceConnection;
|
||||
|
||||
var encoder = voiceConnection.getEncoder({ frameDuration: 20, proxy: true });
|
||||
|
||||
function sendPacket() {
|
||||
var packet = recordedData[0];
|
||||
if (!packet && recordReply) {
|
||||
recordReply("Finished playing");
|
||||
}
|
||||
if (!packet || stopPlaying) {
|
||||
recordingUser = null;
|
||||
return;
|
||||
}
|
||||
var currentTime = (Date.now() - playbackStartTime);
|
||||
var nextTime = packet.playbackTime - currentTime;
|
||||
setTimeout(sendPacket, nextTime);
|
||||
|
||||
if (currentTime < nextTime) return;
|
||||
|
||||
recordedData.shift(packet);
|
||||
var numSamples = opus_packet_get_samples_per_frame(packet.chunk);
|
||||
console.log("playing ", packet.chunk.length, numSamples);
|
||||
encoder.enqueue(packet.chunk, numSamples);
|
||||
}
|
||||
sendPacket();
|
||||
}
|
||||
|
||||
client.Dispatcher.onAny((type, args) => {
|
||||
console.log("\nevent "+type);
|
||||
|
||||
if (args.type == "READY" || args.type == "READY" ||
|
||||
type == "GATEWAY_READY" || type == "ANY_GATEWAY_READY" ||
|
||||
type == "GATEWAY_DISPATCH") {
|
||||
return console.log("e " + (args.type || type));
|
||||
}
|
||||
|
||||
console.log("args " + JSON.stringify(args));
|
||||
});
|
||||
|
||||
// ===========================================================================
|
||||
// Opus helper functions
|
||||
// ===========================================================================
|
||||
|
||||
const Constants = {
|
||||
OPUS_BAD_ARG: -1,
|
||||
OPUS_INVALID_PACKET: -4
|
||||
};
|
||||
|
||||
function opus_packet_get_samples_per_frame(packet, sampleRate) {
|
||||
sampleRate = sampleRate || 48000;
|
||||
|
||||
let audiosize;
|
||||
if (packet[0] & 0x80) {
|
||||
audiosize = ((packet[0] >> 3) & 0x3);
|
||||
audiosize = (sampleRate << audiosize) / 400;
|
||||
} else if ((packet[0] & 0x60) == 0x60) {
|
||||
audiosize = (packet[0] & 0x08) ? sampleRate / 50 : sampleRate / 100;
|
||||
} else {
|
||||
audiosize = ((packet[0] >> 3) & 0x3);
|
||||
if (audiosize == 3) {
|
||||
audiosize = sampleRate * 60 / 1000;
|
||||
} else {
|
||||
audiosize = (sampleRate << audiosize) / 100;
|
||||
}
|
||||
}
|
||||
return audiosize;
|
||||
}
|
||||
|
||||
function opus_packet_get_nb_frames(packet) {
|
||||
var count;
|
||||
if (packet.length < 1) return Constants.OPUS_BAD_ARG;
|
||||
count = packet[0] & 0x3;
|
||||
|
||||
if (count == 0) return 1;
|
||||
else if (count != 3) return 2;
|
||||
else if (packet.length < 2) return Constants.OPUS_INVALID_PACKET;
|
||||
else return packet[1] & 0x3F;
|
||||
}
|
||||
|
||||
function opus_packet_get_nb_samples(packet, sampleRate)
|
||||
{
|
||||
sampleRate = sampleRate || 48000;
|
||||
|
||||
var count = opus_packet_get_nb_frames(packet);
|
||||
if (count < 0) return count;
|
||||
|
||||
var samples = count * opus_packet_get_samples_per_frame(packet, sampleRate);
|
||||
/* Can't have more than 120 ms */
|
||||
if (samples * 25 > sampleRate * 3)
|
||||
return Constants.OPUS_INVALID_PACKET;
|
||||
return samples;
|
||||
}
|
145
node_modules/discordie/examples/echoproxy.js
generated
vendored
Normal file
145
node_modules/discordie/examples/echoproxy.js
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
"use strict";
|
||||
|
||||
// voice echo bot
|
||||
|
||||
// simple audio proxy - mirrors user's audio
|
||||
// can be useful for redirecting audio into another channel/server through
|
||||
// different bot instance
|
||||
|
||||
// commands:
|
||||
// ~!~start - starts proxying audio for the invoker
|
||||
// ~!~stop - stops proxying audio for the invoker
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var Discordie;
|
||||
try { Discordie = require("../"); } catch(e) {}
|
||||
try { Discordie = require("discordie"); } catch(e) {}
|
||||
|
||||
var client = new Discordie({autoReconnect: true});
|
||||
|
||||
var auth = { token: "<BOT-TOKEN>" };
|
||||
try { auth = require("./auth"); } catch(e) {}
|
||||
|
||||
client.connect(auth);
|
||||
|
||||
var proxyingUser = null;
|
||||
|
||||
client.Dispatcher.on("MESSAGE_CREATE", e => {
|
||||
console.log("new message: ");
|
||||
console.log(JSON.stringify(e.message, null, " "));
|
||||
console.log("e.message.content: " + e.message.content);
|
||||
|
||||
const content = e.message.content;
|
||||
const guild = e.message.channel.guild;
|
||||
|
||||
if (content == "~!~start") {
|
||||
if (proxyingUser)
|
||||
return e.message.reply("Already proxying");
|
||||
|
||||
const channelToJoin = e.message.author.getVoiceChannel(guild);
|
||||
if (!channelToJoin)
|
||||
return e.message.reply("Join a voice channel first");
|
||||
|
||||
channelToJoin.join().then(info => {
|
||||
e.message.reply("Proxying audio for user " + e.message.author.username);
|
||||
proxyingUser = e.message.author.id;
|
||||
});
|
||||
}
|
||||
|
||||
if (content == "~!~stop") {
|
||||
e.message.reply("Stopped");
|
||||
proxyingUser = null;
|
||||
}
|
||||
});
|
||||
|
||||
client.Dispatcher.on("VOICE_CONNECTED", e => {
|
||||
var encoder = e.voiceConnection.getEncoder({ frameDuration: 20, proxy: true });
|
||||
var decoder = e.voiceConnection.getDecoder();
|
||||
|
||||
decoder.onPacket = (packet) => {
|
||||
if (!proxyingUser) return;
|
||||
|
||||
const user = e.voiceConnection.ssrcToMember(packet.ssrc);
|
||||
if (!user) return;
|
||||
if (user.id != proxyingUser) return;
|
||||
|
||||
const name = user ? user.username : "<unknown>";
|
||||
console.log(
|
||||
"proxying " + packet.chunk.length +
|
||||
" bytes from " + name +
|
||||
" @ " + packet.timestamp
|
||||
);
|
||||
|
||||
var numSamples = opus_packet_get_samples_per_frame(packet.chunk);
|
||||
encoder.enqueue(packet.chunk, numSamples);
|
||||
};
|
||||
// set callback on `.onPacketDecoded` to enable decoding and
|
||||
// have decoded audio in `packet.chunk`
|
||||
});
|
||||
|
||||
client.Dispatcher.onAny((type, args) => {
|
||||
console.log("\nevent "+type);
|
||||
|
||||
if (args.type == "READY" || args.type == "READY" ||
|
||||
type == "GATEWAY_READY" || type == "ANY_GATEWAY_READY" ||
|
||||
type == "GATEWAY_DISPATCH") {
|
||||
return console.log("e " + (args.type || type));
|
||||
}
|
||||
|
||||
console.log("args " + JSON.stringify(args));
|
||||
});
|
||||
|
||||
// ===========================================================================
|
||||
// Opus helper functions
|
||||
// ===========================================================================
|
||||
|
||||
const Constants = {
|
||||
OPUS_BAD_ARG: -1,
|
||||
OPUS_INVALID_PACKET: -4
|
||||
};
|
||||
|
||||
function opus_packet_get_samples_per_frame(packet, sampleRate) {
|
||||
sampleRate = sampleRate || 48000;
|
||||
|
||||
let audiosize;
|
||||
if (packet[0] & 0x80) {
|
||||
audiosize = ((packet[0] >> 3) & 0x3);
|
||||
audiosize = (sampleRate << audiosize) / 400;
|
||||
} else if ((packet[0] & 0x60) == 0x60) {
|
||||
audiosize = (packet[0] & 0x08) ? sampleRate / 50 : sampleRate / 100;
|
||||
} else {
|
||||
audiosize = ((packet[0] >> 3) & 0x3);
|
||||
if (audiosize == 3) {
|
||||
audiosize = sampleRate * 60 / 1000;
|
||||
} else {
|
||||
audiosize = (sampleRate << audiosize) / 100;
|
||||
}
|
||||
}
|
||||
return audiosize;
|
||||
}
|
||||
|
||||
function opus_packet_get_nb_frames(packet) {
|
||||
var count;
|
||||
if (packet.length < 1) return Constants.OPUS_BAD_ARG;
|
||||
count = packet[0] & 0x3;
|
||||
|
||||
if (count == 0) return 1;
|
||||
else if (count != 3) return 2;
|
||||
else if (packet.length < 2) return Constants.OPUS_INVALID_PACKET;
|
||||
else return packet[1] & 0x3F;
|
||||
}
|
||||
|
||||
function opus_packet_get_nb_samples(packet, sampleRate)
|
||||
{
|
||||
sampleRate = sampleRate || 48000;
|
||||
|
||||
var count = opus_packet_get_nb_frames(packet);
|
||||
if (count < 0) return count;
|
||||
|
||||
var samples = count * opus_packet_get_samples_per_frame(packet, sampleRate);
|
||||
/* Can't have more than 120 ms */
|
||||
if (samples * 25 > sampleRate * 3)
|
||||
return Constants.OPUS_INVALID_PACKET;
|
||||
return samples;
|
||||
}
|
145
node_modules/discordie/examples/encoderstream.js
generated
vendored
Normal file
145
node_modules/discordie/examples/encoderstream.js
generated
vendored
Normal file
@ -0,0 +1,145 @@
|
||||
"use strict";
|
||||
|
||||
//// note: run "npm install lame" in this folder first
|
||||
|
||||
// audio example implemented using AudioEncoderStream
|
||||
|
||||
// audio decoding using "lame"
|
||||
|
||||
// commands:
|
||||
// ping
|
||||
// vjoin <channelname> -- joins matching channel for current guild
|
||||
// vleave
|
||||
// play -- plays test.mp3
|
||||
// stop
|
||||
|
||||
var lame = require('lame');
|
||||
var fs = require('fs');
|
||||
|
||||
var Discordie;
|
||||
try { Discordie = require("../"); } catch(e) {}
|
||||
try { Discordie = require("discordie"); } catch(e) {}
|
||||
|
||||
var client = new Discordie({autoReconnect: true});
|
||||
|
||||
var auth = { token: "<BOT-TOKEN>" };
|
||||
try { auth = require("./auth"); } catch(e) {}
|
||||
|
||||
client.connect(auth);
|
||||
|
||||
client.Dispatcher.on("GATEWAY_READY", e => {
|
||||
const guild = client.Guilds.getBy("name", "test");
|
||||
if (!guild) return console.log("Guild not found");
|
||||
|
||||
const general = guild.voiceChannels.find(c => c.name == "General");
|
||||
if (!general) return console.log("Channel not found");
|
||||
|
||||
return general.join(false, false);
|
||||
});
|
||||
|
||||
client.Dispatcher.on("MESSAGE_CREATE", (e) => {
|
||||
const content = e.message.content;
|
||||
const channel = e.message.channel;
|
||||
const guild = e.message.channel.guild;
|
||||
|
||||
if (content == "ping") {
|
||||
channel.sendMessage("pong");
|
||||
}
|
||||
|
||||
if (content == "vleave") {
|
||||
client.Channels
|
||||
.filter(channel => channel.isGuildVoice && channel.joined)
|
||||
.forEach(channel => channel.leave());
|
||||
}
|
||||
|
||||
if (content.indexOf("vjoin ") == 0) {
|
||||
const targetChannel = content.replace("vjoin ", "");
|
||||
|
||||
var vchannel =
|
||||
guild.voiceChannels
|
||||
.find(channel => channel.name.toLowerCase().indexOf(targetChannel) >= 0);
|
||||
if (vchannel) vchannel.join().then(info => play(info));
|
||||
}
|
||||
|
||||
if (content.indexOf("play") == 0) {
|
||||
if (!client.VoiceConnections.length) {
|
||||
return e.message.reply("Not connected to any channel");
|
||||
}
|
||||
var info = client.VoiceConnections.getForGuild(guild);
|
||||
if (info) play(info);
|
||||
}
|
||||
|
||||
if (content.indexOf("stop") == 0) {
|
||||
var info = client.VoiceConnections.getForGuild(guild);
|
||||
if (info) {
|
||||
var encoderStream = info.voiceConnection.getEncoderStream();
|
||||
encoderStream.unpipeAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.Dispatcher.on("VOICE_CONNECTED", e => {
|
||||
// uncomment to play on join
|
||||
//play();
|
||||
});
|
||||
|
||||
function play(info) {
|
||||
if (!client.VoiceConnections.length) {
|
||||
return console.log("Voice not connected");
|
||||
}
|
||||
|
||||
if (!info) info = client.VoiceConnections[0];
|
||||
|
||||
var mp3decoder = new lame.Decoder();
|
||||
var file = fs.createReadStream("test.mp3");
|
||||
file.pipe(mp3decoder);
|
||||
|
||||
mp3decoder.on('format', pcmfmt => {
|
||||
// note: discordie encoder does resampling if rate != 48000
|
||||
var options = {
|
||||
frameDuration: 60,
|
||||
sampleRate: pcmfmt.sampleRate,
|
||||
channels: pcmfmt.channels,
|
||||
float: false
|
||||
};
|
||||
|
||||
var encoderStream = info.voiceConnection.getEncoderStream(options);
|
||||
if (!encoderStream) {
|
||||
return console.log(
|
||||
"Unable to get encoder stream, connection is disposed"
|
||||
);
|
||||
}
|
||||
|
||||
// Stream instance is persistent until voice connection is disposed;
|
||||
// you can register timestamp listener once when connection is initialized
|
||||
// or access timestamp with `encoderStream.timestamp`
|
||||
encoderStream.resetTimestamp();
|
||||
encoderStream.removeAllListeners("timestamp");
|
||||
encoderStream.on("timestamp", time => console.log("Time " + time));
|
||||
|
||||
// only 1 stream at a time can be piped into AudioEncoderStream
|
||||
// previous stream will automatically unpipe
|
||||
mp3decoder.pipe(encoderStream);
|
||||
mp3decoder.once('end', () => play(info));
|
||||
|
||||
// must be registered after `pipe()`
|
||||
encoderStream.once("unpipe", () => file.destroy());
|
||||
});
|
||||
}
|
||||
|
||||
client.Dispatcher.onAny((type, e) => {
|
||||
var ignore = [
|
||||
"READY",
|
||||
"GATEWAY_READY",
|
||||
"ANY_GATEWAY_READY",
|
||||
"GATEWAY_DISPATCH",
|
||||
"PRESENCE_UPDATE",
|
||||
"TYPING_START",
|
||||
];
|
||||
if (ignore.find(t => (t == type || t == e.type))) {
|
||||
return console.log("<" + type + ">");
|
||||
}
|
||||
|
||||
console.log("\nevent " + type);
|
||||
return console.log("args " + JSON.stringify(e));
|
||||
});
|
120
node_modules/discordie/examples/ffmpegencoder.js
generated
vendored
Normal file
120
node_modules/discordie/examples/ffmpegencoder.js
generated
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
"use strict";
|
||||
|
||||
//// note: install ffmpeg/avconv first
|
||||
|
||||
// audio decoding and encoding using built in ffmpeg wrappers
|
||||
// (opus encoding is done entierly by ffmpeg)
|
||||
|
||||
// commands:
|
||||
// ping
|
||||
// vjoin <channelname> -- joins matching channel for current guild
|
||||
// vleave
|
||||
// play -- plays test.mp3
|
||||
// stop
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var Discordie;
|
||||
try { Discordie = require("../"); } catch(e) {}
|
||||
try { Discordie = require("discordie"); } catch(e) {}
|
||||
|
||||
var client = new Discordie({autoReconnect: true});
|
||||
|
||||
var auth = { token: "<BOT-TOKEN>" };
|
||||
try { auth = require("./auth"); } catch(e) {}
|
||||
|
||||
client.connect(auth);
|
||||
|
||||
client.Dispatcher.on("GATEWAY_READY", e => {
|
||||
const guild = client.Guilds.getBy("name", "test");
|
||||
if (!guild) return console.log("Guild not found");
|
||||
|
||||
const general = guild.voiceChannels.find(c => c.name == "General");
|
||||
if (!general) return console.log("Channel not found");
|
||||
|
||||
return general.join(false, false);
|
||||
});
|
||||
|
||||
client.Dispatcher.on("MESSAGE_CREATE", (e) => {
|
||||
const content = e.message.content;
|
||||
const channel = e.message.channel;
|
||||
const guild = e.message.channel.guild;
|
||||
|
||||
if (content == "ping") {
|
||||
channel.sendMessage("pong");
|
||||
}
|
||||
|
||||
if (content == "vleave") {
|
||||
client.Channels
|
||||
.filter(channel => channel.isGuildVoice && channel.joined)
|
||||
.forEach(channel => channel.leave());
|
||||
}
|
||||
|
||||
if (content.indexOf("vjoin ") == 0) {
|
||||
const targetChannel = content.replace("vjoin ", "");
|
||||
|
||||
var vchannel =
|
||||
guild.voiceChannels
|
||||
.find(channel => channel.name.toLowerCase().indexOf(targetChannel) >= 0);
|
||||
if (vchannel) vchannel.join().then(info => play(info));
|
||||
}
|
||||
|
||||
if (content.indexOf("play") == 0) {
|
||||
if (!client.VoiceConnections.length) {
|
||||
return e.message.reply("Not connected to any channel");
|
||||
}
|
||||
var info = client.VoiceConnections.getForGuild(guild);
|
||||
if (info) play(info);
|
||||
}
|
||||
|
||||
if (content.indexOf("stop") == 0) {
|
||||
var info = client.VoiceConnections.getForGuild(guild);
|
||||
if (info) {
|
||||
var encoderStream = info.voiceConnection.getEncoderStream();
|
||||
encoderStream.unpipeAll();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
client.Dispatcher.on("VOICE_CONNECTED", e => {
|
||||
// uncomment to play on join
|
||||
// play();
|
||||
});
|
||||
|
||||
function play(info) {
|
||||
if (!client.VoiceConnections.length) {
|
||||
return console.log("Voice not connected");
|
||||
}
|
||||
|
||||
if (!info) info = client.VoiceConnections[0];
|
||||
|
||||
var encoder = info.voiceConnection.createExternalEncoder({
|
||||
type: "ffmpeg",
|
||||
source: "test.mp3"
|
||||
});
|
||||
if (!encoder) return console.log("Voice connection is no longer valid");
|
||||
|
||||
encoder.once("end", () => play(info));
|
||||
|
||||
var encoderStream = encoder.play();
|
||||
encoderStream.resetTimestamp();
|
||||
encoderStream.removeAllListeners("timestamp");
|
||||
encoderStream.on("timestamp", time => console.log("Time " + time));
|
||||
}
|
||||
|
||||
client.Dispatcher.onAny((type, e) => {
|
||||
var ignore = [
|
||||
"READY",
|
||||
"GATEWAY_READY",
|
||||
"ANY_GATEWAY_READY",
|
||||
"GATEWAY_DISPATCH",
|
||||
"PRESENCE_UPDATE",
|
||||
"TYPING_START",
|
||||
];
|
||||
if (ignore.find(t => (t == type || t == e.type))) {
|
||||
return console.log("<" + type + ">");
|
||||
}
|
||||
|
||||
console.log("\nevent " + type);
|
||||
return console.log("args " + JSON.stringify(e));
|
||||
});
|
193
node_modules/discordie/examples/lowlevelaudio/massive.js
generated
vendored
Normal file
193
node_modules/discordie/examples/lowlevelaudio/massive.js
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
"use strict";
|
||||
|
||||
//// note: run "npm install lame" in this folder first
|
||||
|
||||
// example bot
|
||||
|
||||
// audio decoding using "lame"
|
||||
|
||||
// commands:
|
||||
// ping
|
||||
// vjoin <channelname> -- joins matching channel for current guild
|
||||
// vleave
|
||||
// play -- plays test.mp3
|
||||
// stop
|
||||
|
||||
var lame = require('lame');
|
||||
var fs = require('fs');
|
||||
|
||||
var Discordie;
|
||||
try { Discordie = require("../../"); } catch(e) {}
|
||||
try { Discordie = require("discordie"); } catch(e) {}
|
||||
|
||||
var client = new Discordie({autoReconnect: true});
|
||||
|
||||
var auth = { token: "<BOT-TOKEN>" };
|
||||
try { auth = require("./auth"); } catch(e) {}
|
||||
|
||||
function connect() { client.connect(auth); }
|
||||
connect();
|
||||
|
||||
client.Dispatcher.on(Discordie.Events.GATEWAY_READY, (e) => {
|
||||
// client.Users
|
||||
// client.Channels
|
||||
// client.DirectMessageChannels
|
||||
// client.Guilds
|
||||
// client.Messages
|
||||
// are collection interfaces with filter(fn), get(id), getBy(k, v)
|
||||
|
||||
// client.User
|
||||
// contains current user
|
||||
|
||||
const guild = client.Guilds.getBy("name", "test");
|
||||
// or:
|
||||
// client.Guilds.filter(g => (g.name == "test"))[0];
|
||||
|
||||
// e.data contains raw READY event
|
||||
|
||||
if (guild) {
|
||||
// guild.voiceChannels returns an array
|
||||
const general = guild.voiceChannels.filter(c => c.name == "General")[0];
|
||||
|
||||
// IVoiceChannel.join(selfMute, selfDeaf)
|
||||
if (general)
|
||||
return general.join(false, false);
|
||||
|
||||
return console.log("Channel not found");
|
||||
}
|
||||
console.log("Guild not found");
|
||||
});
|
||||
|
||||
client.Dispatcher.on(Discordie.Events.MESSAGE_CREATE, (e) => {
|
||||
console.log("new message: ");
|
||||
console.log(JSON.stringify(e.message, null, " "));
|
||||
console.log("e.message.content: " + e.message.content);
|
||||
|
||||
if(e.message.content == "ping") {
|
||||
e.message.channel.sendMessage("pong");
|
||||
|
||||
// e.message.reply("pong")
|
||||
// will prefix the message with a mention
|
||||
}
|
||||
if(e.message.content == "vleave") {
|
||||
var c = e.message.channel;
|
||||
|
||||
client.Channels
|
||||
.filter(channel => channel.isGuildVoice && channel.joined)
|
||||
.forEach(channel => channel.leave());
|
||||
}
|
||||
if(e.message.content.indexOf("vjoin ") == 0) {
|
||||
const targetChannel = e.message.content.replace("vjoin ", "");
|
||||
|
||||
e.message.channel.guild.voiceChannels
|
||||
.forEach(channel => {
|
||||
if(channel.name.toLowerCase().indexOf(targetChannel) >= 0)
|
||||
channel.join().then(v => play(v));
|
||||
// channel.join() returns a promise with voiceConnectionInfo
|
||||
});
|
||||
}
|
||||
if(e.message.content.indexOf("play") == 0) {
|
||||
if(!client.VoiceConnections.length) {
|
||||
return e.message.reply("Not connected to any channel");
|
||||
}
|
||||
play();
|
||||
}
|
||||
if(e.message.content.indexOf("stop") == 0) {
|
||||
stopPlaying = true;
|
||||
}
|
||||
});
|
||||
client.Dispatcher.on(Discordie.Events.MESSAGE_UPDATE, (e) => {
|
||||
console.log("updated message: ");
|
||||
console.log(JSON.stringify(e.message));
|
||||
});
|
||||
client.Dispatcher.on(Discordie.Events.MESSAGE_DELETE, (e) => {
|
||||
console.log("deleted message: ");
|
||||
console.log(JSON.stringify(e.message));
|
||||
|
||||
// e.message now has 'e.message.deleted' set to true
|
||||
// properties in e.message will be null if the message is not cached
|
||||
});
|
||||
|
||||
client.Dispatcher.on(Discordie.Events.VOICE_CONNECTED, (data) => {
|
||||
if(client.VoiceConnections.length <= 0) {
|
||||
return console.log("Voice not connected");
|
||||
}
|
||||
|
||||
// uncomment to play on join
|
||||
//play();
|
||||
});
|
||||
|
||||
var stopPlaying = false;
|
||||
function play(voiceConnectionInfo) {
|
||||
stopPlaying = false;
|
||||
|
||||
var mp3decoder = new lame.Decoder();
|
||||
mp3decoder.on('format', decode);
|
||||
fs.createReadStream("test.mp3").pipe(mp3decoder);
|
||||
|
||||
function decode(pcmfmt) {
|
||||
// note: discordie encoder does resampling if rate != 48000
|
||||
var options = {
|
||||
frameDuration: 60,
|
||||
sampleRate: pcmfmt.sampleRate,
|
||||
channels: pcmfmt.channels,
|
||||
float: false
|
||||
};
|
||||
|
||||
const frameDuration = 60;
|
||||
|
||||
var readSize =
|
||||
pcmfmt.sampleRate / 1000 *
|
||||
options.frameDuration *
|
||||
pcmfmt.bitDepth / 8 *
|
||||
pcmfmt.channels;
|
||||
|
||||
mp3decoder.once('readable', function() {
|
||||
if(!client.VoiceConnections.length) {
|
||||
return console.log("Voice not connected");
|
||||
}
|
||||
|
||||
if(!voiceConnectionInfo) {
|
||||
// get first if not specified
|
||||
voiceConnectionInfo = client.VoiceConnections[0];
|
||||
}
|
||||
var voiceConnection = voiceConnectionInfo.voiceConnection;
|
||||
|
||||
// one encoder per voice connection
|
||||
var encoder = voiceConnection.getEncoder(options);
|
||||
|
||||
const needBuffer = () => encoder.onNeedBuffer();
|
||||
encoder.onNeedBuffer = function() {
|
||||
var chunk = mp3decoder.read(readSize);
|
||||
if (stopPlaying) return;
|
||||
|
||||
// delay the packet if no data buffered
|
||||
if (!chunk) return setTimeout(needBuffer, options.frameDuration);
|
||||
|
||||
var sampleCount = readSize / pcmfmt.channels / (pcmfmt.bitDepth / 8);
|
||||
encoder.enqueue(chunk, sampleCount);
|
||||
};
|
||||
|
||||
needBuffer();
|
||||
});
|
||||
|
||||
mp3decoder.once('end', () => setTimeout(play, 100, voiceConnectionInfo));
|
||||
}
|
||||
}
|
||||
|
||||
client.Dispatcher.onAny((type, e) => {
|
||||
var ignore = [
|
||||
"READY",
|
||||
"GATEWAY_READY",
|
||||
"ANY_GATEWAY_READY",
|
||||
"GATEWAY_DISPATCH",
|
||||
"PRESENCE_UPDATE",
|
||||
"TYPING_START",
|
||||
];
|
||||
if(ignore.find(t => (t == type || t == e.type))) {
|
||||
return console.log("<" + type + ">");
|
||||
}
|
||||
|
||||
console.log("\nevent " + type);
|
||||
return console.log("args " + JSON.stringify(e));
|
||||
});
|
238
node_modules/discordie/examples/lowlevelaudio/massive2.js
generated
vendored
Normal file
238
node_modules/discordie/examples/lowlevelaudio/massive2.js
generated
vendored
Normal file
@ -0,0 +1,238 @@
|
||||
"use strict";
|
||||
|
||||
//// note: install ffmpeg/avconv first
|
||||
|
||||
// example bot
|
||||
|
||||
// commands:
|
||||
// ping
|
||||
// vjoin <channelname> -- joins matching channel for current guild
|
||||
// vleave
|
||||
// play -- plays test.mp3
|
||||
// stop
|
||||
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var child_process = require('child_process');
|
||||
|
||||
var Discordie;
|
||||
try { Discordie = require("../../"); } catch(e) {}
|
||||
try { Discordie = require("discordie"); } catch(e) {}
|
||||
|
||||
var client = new Discordie({autoReconnect: true});
|
||||
|
||||
var auth = { token: "<BOT-TOKEN>" };
|
||||
try { auth = require("./auth"); } catch(e) {}
|
||||
|
||||
function connect() { client.connect(auth); }
|
||||
connect();
|
||||
|
||||
client.Dispatcher.on(Discordie.Events.GATEWAY_READY, (e) => {
|
||||
// client.Users
|
||||
// client.Channels
|
||||
// client.DirectMessageChannels
|
||||
// client.Guilds
|
||||
// client.Messages
|
||||
// are collection interfaces with filter(fn), get(id), getBy(k, v)
|
||||
|
||||
// client.User
|
||||
// contains current user
|
||||
|
||||
const guild = client.Guilds.getBy("name", "test");
|
||||
// or:
|
||||
// client.Guilds.filter(g => (g.name == "test"))[0];
|
||||
|
||||
// e.data contains raw READY event
|
||||
|
||||
if (guild) {
|
||||
// guild.voiceChannels returns an array
|
||||
const general = guild.voiceChannels.filter(c => c.name == "General")[0];
|
||||
|
||||
// IVoiceChannel.join(selfMute, selfDeaf)
|
||||
if (general)
|
||||
return general.join(false, false);
|
||||
|
||||
return console.log("Channel not found");
|
||||
}
|
||||
console.log("Guild not found");
|
||||
});
|
||||
|
||||
client.Dispatcher.on(Discordie.Events.MESSAGE_CREATE, (e) => {
|
||||
console.log("new message: ");
|
||||
console.log(JSON.stringify(e.message, null, " "));
|
||||
console.log("e.message.content: " + e.message.content);
|
||||
|
||||
if(e.message.content == "ping") {
|
||||
e.message.channel.sendMessage("pong");
|
||||
|
||||
// e.message.reply("pong")
|
||||
// will prefix the message with a mention
|
||||
}
|
||||
if(e.message.content == "vleave") {
|
||||
var c = e.message.channel;
|
||||
|
||||
client.Channels
|
||||
.filter(channel => channel.isGuildVoice && channel.joined)
|
||||
.forEach(channel => channel.leave());
|
||||
}
|
||||
if(e.message.content.indexOf("vjoin ") == 0) {
|
||||
const targetChannel = e.message.content.replace("vjoin ", "");
|
||||
|
||||
e.message.channel.guild.voiceChannels
|
||||
.forEach(channel => {
|
||||
if(channel.name.toLowerCase().indexOf(targetChannel) >= 0)
|
||||
channel.join().then(v => play(v));
|
||||
// channel.join() returns a promise with voiceConnectionInfo
|
||||
});
|
||||
}
|
||||
if(e.message.content.indexOf("play") == 0) {
|
||||
if(!client.VoiceConnections.length) {
|
||||
return e.message.reply("Not connected to any channel");
|
||||
}
|
||||
play();
|
||||
}
|
||||
if(e.message.content.indexOf("stop") == 0) {
|
||||
stop();
|
||||
}
|
||||
});
|
||||
client.Dispatcher.on(Discordie.Events.MESSAGE_UPDATE, (e) => {
|
||||
console.log("updated message: ");
|
||||
console.log(JSON.stringify(e.message));
|
||||
});
|
||||
client.Dispatcher.on(Discordie.Events.MESSAGE_DELETE, (e) => {
|
||||
console.log("deleted message: ");
|
||||
console.log(JSON.stringify(e.message));
|
||||
|
||||
// e.message now has 'e.message.deleted' set to true
|
||||
// properties in e.message will be null if the message is not cached
|
||||
});
|
||||
|
||||
client.Dispatcher.on(Discordie.Events.VOICE_CONNECTED, (data) => {
|
||||
if(client.VoiceConnections.length <= 0) {
|
||||
return console.log("Voice not connected");
|
||||
}
|
||||
|
||||
// uncomment to play on join
|
||||
//play();
|
||||
});
|
||||
|
||||
function getConverter(args, options) {
|
||||
var binaries = [
|
||||
'ffmpeg',
|
||||
'ffmpeg.exe',
|
||||
'avconv',
|
||||
'avconv.exe'
|
||||
];
|
||||
|
||||
var paths = process.env.PATH.split(path.delimiter).concat(["."]);
|
||||
|
||||
for (var name of binaries) {
|
||||
for (var p of paths) {
|
||||
var binary = p + path.sep + name;
|
||||
if (!fs.existsSync(binary)) continue;
|
||||
return child_process.spawn(name, args, options);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
var ffmpeg = null;
|
||||
function stop() {
|
||||
stopPlaying = true;
|
||||
if (!ffmpeg) return;
|
||||
ffmpeg.kill();
|
||||
ffmpeg = null;
|
||||
}
|
||||
|
||||
var stopPlaying = false;
|
||||
function play(voiceConnectionInfo) {
|
||||
stopPlaying = false;
|
||||
|
||||
var sampleRate = 48000;
|
||||
var bitDepth = 16;
|
||||
var channels = 2;
|
||||
|
||||
if (ffmpeg) ffmpeg.kill();
|
||||
|
||||
ffmpeg = getConverter([
|
||||
"-re",
|
||||
"-i", "test.mp3",
|
||||
"-f", "s16le",
|
||||
"-ar", sampleRate,
|
||||
"-ac", channels,
|
||||
"-"
|
||||
], {stdio: ['pipe', 'pipe', 'ignore']});
|
||||
if (!ffmpeg) return console.log("ffmpeg/avconv not found");
|
||||
|
||||
var _ffmpeg = ffmpeg;
|
||||
var ff = ffmpeg.stdout;
|
||||
|
||||
// note: discordie encoder does resampling if rate != 48000
|
||||
var options = {
|
||||
frameDuration: 60,
|
||||
sampleRate: sampleRate,
|
||||
channels: channels,
|
||||
float: false
|
||||
};
|
||||
|
||||
const frameDuration = 60;
|
||||
|
||||
var readSize =
|
||||
sampleRate / 1000 *
|
||||
options.frameDuration *
|
||||
bitDepth / 8 *
|
||||
channels;
|
||||
|
||||
ff.once('readable', function() {
|
||||
if(!client.VoiceConnections.length) {
|
||||
return console.log("Voice not connected");
|
||||
}
|
||||
|
||||
if(!voiceConnectionInfo) {
|
||||
// get first if not specified
|
||||
voiceConnectionInfo = client.VoiceConnections[0];
|
||||
}
|
||||
var voiceConnection = voiceConnectionInfo.voiceConnection;
|
||||
|
||||
// one encoder per voice connection
|
||||
var encoder = voiceConnection.getEncoder(options);
|
||||
|
||||
const needBuffer = () => encoder.onNeedBuffer();
|
||||
encoder.onNeedBuffer = function() {
|
||||
var chunk = ff.read(readSize);
|
||||
|
||||
if (_ffmpeg.killed) return;
|
||||
if (stopPlaying) return stop();
|
||||
|
||||
// delay the packet if no data buffered
|
||||
if (!chunk) return setTimeout(needBuffer, options.frameDuration);
|
||||
|
||||
var sampleCount = readSize / channels / (bitDepth / 8);
|
||||
encoder.enqueue(chunk, sampleCount);
|
||||
};
|
||||
|
||||
needBuffer();
|
||||
});
|
||||
|
||||
ff.once('end', () => {
|
||||
if (stopPlaying) return;
|
||||
setTimeout(play, 100, voiceConnectionInfo);
|
||||
});
|
||||
}
|
||||
|
||||
client.Dispatcher.onAny((type, e) => {
|
||||
var ignore = [
|
||||
"READY",
|
||||
"GATEWAY_READY",
|
||||
"ANY_GATEWAY_READY",
|
||||
"GATEWAY_DISPATCH",
|
||||
"PRESENCE_UPDATE",
|
||||
"TYPING_START",
|
||||
];
|
||||
if(ignore.find(t => (t == type || t == e.type))) {
|
||||
return console.log("<" + type + ">");
|
||||
}
|
||||
|
||||
console.log("\nevent " + type);
|
||||
return console.log("args " + JSON.stringify(e));
|
||||
});
|
227
node_modules/discordie/examples/permissions.js
generated
vendored
Normal file
227
node_modules/discordie/examples/permissions.js
generated
vendored
Normal file
@ -0,0 +1,227 @@
|
||||
"use strict";
|
||||
|
||||
// example bot
|
||||
|
||||
// commands:
|
||||
// ping
|
||||
// do - creates a role Testing, assigns it to the member, adds member permission for channel
|
||||
// undo
|
||||
|
||||
var Discordie;
|
||||
try { Discordie = require("../"); } catch(e) {}
|
||||
try { Discordie = require("discordie"); } catch(e) {}
|
||||
|
||||
var client = new Discordie({autoReconnect: true});
|
||||
var Events = Discordie.Events;
|
||||
|
||||
var auth = { token: "<BOT-TOKEN>" };
|
||||
try { auth = require("./auth"); } catch(e) {}
|
||||
|
||||
client.connect(auth);
|
||||
|
||||
client.Dispatcher.on("GATEWAY_READY", e => {
|
||||
console.log("Ready");
|
||||
});
|
||||
|
||||
client.Dispatcher.on("MESSAGE_CREATE", e => {
|
||||
console.log("new message: ");
|
||||
console.log(JSON.stringify(e.message, null, " "));
|
||||
console.log("e.message.content: " + e.message.content);
|
||||
|
||||
var content = e.message.content;
|
||||
|
||||
if (content === "ping") channel.sendMessage("pong");
|
||||
if (content === "do") doCommand(e);
|
||||
if (content === "undo") undoCommand(e);
|
||||
});
|
||||
|
||||
function onError(e) {
|
||||
if (!e) return console.error("Unknown error");
|
||||
|
||||
if(e.response && e.response.error)
|
||||
return console.error(e.response.error);
|
||||
|
||||
console.error(e.toString());
|
||||
}
|
||||
|
||||
function doCommand(e) {
|
||||
var guild = e.message.guild;
|
||||
var channel = e.message.channel;
|
||||
var member = e.message.member;
|
||||
|
||||
// chain of actions
|
||||
console.log(" >> creating role");
|
||||
|
||||
guild.createRole()
|
||||
.then(assignRole)
|
||||
.catch(onError);
|
||||
|
||||
function assignRole(role) {
|
||||
console.log(" >> assigning role");
|
||||
|
||||
member.assignRole(role)
|
||||
.then(() => setRolePermissions(role))
|
||||
.catch(onError);
|
||||
}
|
||||
function setRolePermissions(role) {
|
||||
console.log(" >> setting role permissions");
|
||||
|
||||
/*
|
||||
List of role permissions:
|
||||
General: {
|
||||
CREATE_INSTANT_INVITE,
|
||||
KICK_MEMBERS,
|
||||
BAN_MEMBERS,
|
||||
ADMINISTRATOR,
|
||||
MANAGE_CHANNELS,
|
||||
MANAGE_GUILD,
|
||||
CHANGE_NICKNAME,
|
||||
MANAGE_NICKNAMES,
|
||||
MANAGE_ROLES,
|
||||
MANAGE_WEBHOOKS,
|
||||
MANAGE_EMOJIS,
|
||||
},
|
||||
Text: {
|
||||
READ_MESSAGES,
|
||||
SEND_MESSAGES,
|
||||
SEND_TTS_MESSAGES,
|
||||
MANAGE_MESSAGES,
|
||||
EMBED_LINKS,
|
||||
ATTACH_FILES,
|
||||
READ_MESSAGE_HISTORY,
|
||||
MENTION_EVERYONE,
|
||||
EXTERNAL_EMOTES,
|
||||
ADD_REACTIONS,
|
||||
},
|
||||
Voice: {
|
||||
CONNECT,
|
||||
SPEAK,
|
||||
MUTE_MEMBERS,
|
||||
DEAFEN_MEMBERS,
|
||||
MOVE_MEMBERS,
|
||||
USE_VAD,
|
||||
}
|
||||
*/
|
||||
|
||||
var perms = role.permissions;
|
||||
perms.General.KICK_MEMBERS = true;
|
||||
perms.General.BAN_MEMBERS = true;
|
||||
perms.Text.MENTION_EVERYONE = true;
|
||||
|
||||
// 'role.permissions' object resets on error
|
||||
|
||||
var newRoleName = "Testing";
|
||||
var color = 0xE74C3C; // RED
|
||||
var hoist = true; // show separate group
|
||||
|
||||
role.commit(newRoleName, color, hoist)
|
||||
.then(createChannelPermissions)
|
||||
.catch(onError);
|
||||
}
|
||||
function createChannelPermissions() {
|
||||
console.log(" >> creating channel permissions");
|
||||
|
||||
channel.createPermissionOverwrite(member)
|
||||
.then(setChannelPermissions)
|
||||
.catch(onError);
|
||||
}
|
||||
function setChannelPermissions(overwrite) {
|
||||
console.log(" >> setting channel permissions");
|
||||
|
||||
var allow = overwrite.allow;
|
||||
var deny = overwrite.deny;
|
||||
|
||||
/*
|
||||
List of channel permissions:
|
||||
General: {
|
||||
CREATE_INSTANT_INVITE,
|
||||
MANAGE_CHANNEL,
|
||||
MANAGE_PERMISSIONS
|
||||
},
|
||||
Text: {
|
||||
READ_MESSAGES,
|
||||
SEND_MESSAGES,
|
||||
SEND_TTS_MESSAGES,
|
||||
MANAGE_MESSAGES,
|
||||
EMBED_LINKS,
|
||||
ATTACH_FILES,
|
||||
READ_MESSAGE_HISTORY,
|
||||
MENTION_EVERYONE,
|
||||
},
|
||||
Voice: {
|
||||
CONNECT,
|
||||
SPEAK,
|
||||
MUTE_MEMBERS,
|
||||
DEAFEN_MEMBERS,
|
||||
MOVE_MEMBERS,
|
||||
USE_VAD,
|
||||
}
|
||||
*/
|
||||
|
||||
// .Text only exists for text channels
|
||||
// .Voice only exists for voice channels
|
||||
// .General exists for both
|
||||
|
||||
allow.General.MANAGE_CHANNEL = true;
|
||||
allow.General.MANAGE_PERMISSIONS = true;
|
||||
|
||||
overwrite.commit()
|
||||
.then((overwrite) => console.log(" >> finished"))
|
||||
.catch(onError);
|
||||
}
|
||||
}
|
||||
|
||||
function undoCommand(e) {
|
||||
var channel = e.message.channel;
|
||||
var member = e.message.member;
|
||||
|
||||
removeOverwrite();
|
||||
function removeOverwrite() {
|
||||
console.log(" >> removing overwrite");
|
||||
var overwrites = channel.permission_overwrites;
|
||||
var overwrite = overwrites.find(o => (o.id == member.id));
|
||||
if (!overwrite) {
|
||||
console.log(" >> no overwrite");
|
||||
unassignRoleTesting();
|
||||
return;
|
||||
}
|
||||
overwrite.delete()
|
||||
.then(unassignRoleTesting)
|
||||
.catch(onError);
|
||||
}
|
||||
function unassignRoleTesting() {
|
||||
console.log(" >> unassigning role");
|
||||
var role = member.roles.find(r => r.name == "Testing");
|
||||
if (!role) {
|
||||
console.log(" >> no role, finished");
|
||||
return;
|
||||
}
|
||||
member.unassignRole(role)
|
||||
.then(() => deleteRoleTesting(role))
|
||||
.catch(onError);
|
||||
}
|
||||
function deleteRoleTesting(role) {
|
||||
console.log(" >> unassigning role");
|
||||
|
||||
role.delete()
|
||||
.then((overwrite) => console.log(" >> finished"))
|
||||
.catch(onError);
|
||||
}
|
||||
}
|
||||
|
||||
client.Dispatcher.onAny((type, e) => {
|
||||
var ignore = [
|
||||
"READY",
|
||||
"GATEWAY_READY",
|
||||
"ANY_GATEWAY_READY",
|
||||
"GATEWAY_DISPATCH",
|
||||
"PRESENCE_UPDATE",
|
||||
"TYPING_START",
|
||||
];
|
||||
if(ignore.find(t => (t == type || t == e.type))) {
|
||||
return console.log("<" + type + ">");
|
||||
}
|
||||
|
||||
console.log("\nevent " + type);
|
||||
return console.log("args " + JSON.stringify(e));
|
||||
});
|
873
node_modules/discordie/lib/Constants.js
generated
vendored
Normal file
873
node_modules/discordie/lib/Constants.js
generated
vendored
Normal file
@ -0,0 +1,873 @@
|
||||
"use strict";
|
||||
|
||||
const Permissions = {
|
||||
General: {
|
||||
CREATE_INSTANT_INVITE: 1 << 0,
|
||||
KICK_MEMBERS: 1 << 1,
|
||||
BAN_MEMBERS: 1 << 2,
|
||||
ADMINISTRATOR: 1 << 3,
|
||||
MANAGE_CHANNELS: 1 << 4,
|
||||
MANAGE_GUILD: 1 << 5,
|
||||
CHANGE_NICKNAME: 1 << 26,
|
||||
MANAGE_NICKNAMES: 1 << 27,
|
||||
MANAGE_ROLES: 1 << 28,
|
||||
MANAGE_WEBHOOKS: 1 << 29,
|
||||
MANAGE_EMOJIS: 1 << 30,
|
||||
},
|
||||
Text: {
|
||||
READ_MESSAGES: 1 << 10,
|
||||
SEND_MESSAGES: 1 << 11,
|
||||
SEND_TTS_MESSAGES: 1 << 12,
|
||||
MANAGE_MESSAGES: 1 << 13,
|
||||
EMBED_LINKS: 1 << 14,
|
||||
ATTACH_FILES: 1 << 15,
|
||||
READ_MESSAGE_HISTORY: 1 << 16,
|
||||
MENTION_EVERYONE: 1 << 17,
|
||||
EXTERNAL_EMOTES: 1 << 18,
|
||||
ADD_REACTIONS: 1 << 6,
|
||||
},
|
||||
Voice: {
|
||||
CONNECT: 1 << 20,
|
||||
SPEAK: 1 << 21,
|
||||
MUTE_MEMBERS: 1 << 22,
|
||||
DEAFEN_MEMBERS: 1 << 23,
|
||||
MOVE_MEMBERS: 1 << 24,
|
||||
USE_VAD: 1 << 25,
|
||||
}
|
||||
};
|
||||
|
||||
const ChannelGeneral = {
|
||||
CREATE_INSTANT_INVITE: Permissions.General.CREATE_INSTANT_INVITE,
|
||||
MANAGE_CHANNEL: Permissions.General.MANAGE_CHANNELS,
|
||||
MANAGE_PERMISSIONS: Permissions.General.MANAGE_ROLES
|
||||
};
|
||||
const PermissionSpecs = {
|
||||
Role: Permissions,
|
||||
TextChannel: {
|
||||
General: ChannelGeneral,
|
||||
Text: Permissions.Text
|
||||
},
|
||||
VoiceChannel: {
|
||||
General: ChannelGeneral,
|
||||
Voice: Permissions.Voice
|
||||
}
|
||||
};
|
||||
const PermissionsDefault = [
|
||||
Permissions.General.CREATE_INSTANT_INVITE,
|
||||
Permissions.General.CHANGE_NICKNAME,
|
||||
Permissions.Text.READ_MESSAGES,
|
||||
Permissions.Text.SEND_MESSAGES,
|
||||
Permissions.Text.SEND_TTS_MESSAGES,
|
||||
Permissions.Text.EMBED_LINKS,
|
||||
Permissions.Text.ATTACH_FILES,
|
||||
Permissions.Text.READ_MESSAGE_HISTORY,
|
||||
Permissions.Text.MENTION_EVERYONE,
|
||||
Permissions.Text.EXTERNAL_EMOTES,
|
||||
Permissions.Text.ADD_REACTIONS,
|
||||
Permissions.Voice.CONNECT,
|
||||
Permissions.Voice.SPEAK,
|
||||
Permissions.Voice.USE_VAD
|
||||
].reduce((perms, perm) => perms | perm, 0);
|
||||
|
||||
const Constants = {
|
||||
ReadyState: {
|
||||
CONNECTING: 0,
|
||||
OPEN: 1,
|
||||
CLOSING: 2,
|
||||
CLOSED: 3,
|
||||
},
|
||||
DiscordieState: {
|
||||
DISCONNECTED: 0,
|
||||
LOGGING_IN: 0,
|
||||
LOGGED_IN: 0,
|
||||
CONNECTING: 0,
|
||||
CONNECTED: 0,
|
||||
},
|
||||
Errors: {
|
||||
VOICE_DISCONNECTED_FROM_GATEWAY:
|
||||
error => `Disconnected from gateway socket: ${error}`,
|
||||
VOICE_SESSION_INVALIDATED:
|
||||
`Session has been invalidated`,
|
||||
VOICE_CHANGING_SERVER:
|
||||
"Changing server",
|
||||
VOICE_SESSION_DESCRIPTION_TIMEOUT:
|
||||
"Failed to connect to voice: VOICE_SESSION_DESCRIPTION timed out",
|
||||
VOICE_TRANSPORT_TIMEOUT:
|
||||
"Voice transport timed out",
|
||||
VOICE_KICKED_FROM_CHANNEL:
|
||||
"Kicked from the voice channel",
|
||||
VOICE_CONNECTED_FROM_ANOTHER_LOCATION:
|
||||
"Connected from another location",
|
||||
VOICE_GUILD_UNAVAILABLE:
|
||||
"Guild unavailable",
|
||||
VOICE_CALL_UNAVAILABLE:
|
||||
"Call unavailable",
|
||||
VOICE_MANUAL_DISCONNECT:
|
||||
"Manual disconnect"
|
||||
},
|
||||
Events: {
|
||||
// =============================== INTERNAL ===============================
|
||||
GATEWAY_OPEN: 0,
|
||||
GATEWAY_HELLO: 0,
|
||||
GATEWAY_DISPATCH: 0,
|
||||
GATEWAY_DISCONNECT: 0,
|
||||
GATEWAY_UNHANDLED_MESSAGE: 0,
|
||||
|
||||
VOICESOCKET_OPEN: 0,
|
||||
VOICESOCKET_DISCONNECT: 0,
|
||||
VOICESOCKET_UNHANDLED_MESSAGE: 0,
|
||||
|
||||
VOICE_READY: 0,
|
||||
VOICE_SESSION_DESCRIPTION: 0,
|
||||
VOICE_SPEAKING: 0,
|
||||
|
||||
COLLECTION_READY: 0,
|
||||
READY_TASK_FINISHED: 0,
|
||||
|
||||
LOADED_MORE_MESSAGES: 0,
|
||||
LOADED_PINNED_MESSAGES: 0,
|
||||
LOADED_GUILD_BANS: 0,
|
||||
|
||||
ANY_GATEWAY_READY: 0, // fires on every gateway (primary and secondary)
|
||||
// No secondary gateways as of botapi multiserver voice release @2016-03-11
|
||||
|
||||
// ================================= REST =================================
|
||||
REQUEST_AUTH_LOGIN_ERROR: 0, REQUEST_AUTH_LOGIN_SUCCESS: 0,
|
||||
REQUEST_GATEWAY_ERROR: 0, REQUEST_GATEWAY_SUCCESS: 0,
|
||||
|
||||
// ================================ CUSTOM ================================
|
||||
|
||||
/**
|
||||
* Emitted when login or gateway auth failed,
|
||||
* or primary gateway socket disconnects, closing all open sockets.
|
||||
*
|
||||
* Not emitted if disconnected using `client.disconnect()`.
|
||||
*
|
||||
* Property `error` can contain following `Error` messages:
|
||||
*
|
||||
* - ** `"Login failed"` **
|
||||
*
|
||||
* Set if REST `/login` endpoint returned an error.
|
||||
*
|
||||
* - ** `"Could not get gateway"` **
|
||||
*
|
||||
* Set if REST `/gateway` endpoint returned an error.
|
||||
*
|
||||
* - ** `"No token specified"` **
|
||||
*
|
||||
* Should never fire under normal circumstances.
|
||||
* Set if attempted to open gateway socket without token.
|
||||
*
|
||||
* - ** `"Heartbeat ACK did not arrive in time"` **
|
||||
*
|
||||
* - ** `"Failed to connect to gateway: READY timed out"` **
|
||||
*
|
||||
* Set if server did not return a `READY` (initialization) packet
|
||||
* within 5 minutes.
|
||||
*
|
||||
* - ** `"Disconnected from primary gateway"` **
|
||||
*
|
||||
* Emitted for any other errors. Property `error.exception` will contain
|
||||
* the `Number` error code from websocket.
|
||||
*
|
||||
* Original `Error` object or `Number` error code is stored
|
||||
* within `DiscordieError` and can be inspected using `error.exception`.
|
||||
* @event DISCONNECTED
|
||||
* @property {DiscordieError} error
|
||||
* @property {Boolean} [autoReconnect]
|
||||
* Only present (and set to true) when auto-reconnect is enabled.
|
||||
* @property {Number} [delay]
|
||||
* Delay in milliseconds until next reconnect attempt.
|
||||
* Only present when auto-reconnect is enabled.
|
||||
*/
|
||||
DISCONNECTED: 0,
|
||||
|
||||
/**
|
||||
* Emitted when the `Discordie` instance is ready to use.
|
||||
*
|
||||
* All objects except unavailable guilds and offline members of large guilds
|
||||
* (250+ members) will be in cache when this event fires.
|
||||
*
|
||||
* You can request offline members using `client.Users.fetchMembers()`.
|
||||
* See documentation for `IUserCollection.fetchMembers`.
|
||||
*
|
||||
* > **Note: Any other events may fire before `GATEWAY_READY`.**
|
||||
* @event GATEWAY_READY
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {Object} data - Raw event data
|
||||
* @example
|
||||
* var client = new Discordie();
|
||||
* client.connect({ token: "bot_token" });
|
||||
* client.Dispatcher.on("GATEWAY_READY", e => {
|
||||
* // all objects except offline members of large guilds
|
||||
* // have been cached at this point
|
||||
* });
|
||||
*/
|
||||
GATEWAY_READY: 0, // fires only on primary gateway
|
||||
|
||||
/**
|
||||
* Emitted after gateway connection is resumed after a disconnect.
|
||||
*
|
||||
* Connections can be resumable if disconnected for short period of time.
|
||||
*
|
||||
* Does not clear cache unlike `GATEWAY_READY`.
|
||||
* @event GATEWAY_RESUMED
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {Object} data - Raw event data
|
||||
*/
|
||||
GATEWAY_RESUMED: 0,
|
||||
|
||||
/**
|
||||
* Emitted when a new voice connection is fully initialized.
|
||||
* @event VOICE_CONNECTED
|
||||
* @property {VoiceSocket} socket
|
||||
* @property {IVoiceConnection} voiceConnection
|
||||
*/
|
||||
VOICE_CONNECTED: 0,
|
||||
/**
|
||||
* Emitted when a voice socket disconnects.
|
||||
*
|
||||
* Property `error` can contain `null` or following `Error` messages:
|
||||
*
|
||||
* - ** `` `Disconnected from gateway socket: ${errorCode}` `` **
|
||||
*
|
||||
* Set when an error occured on gateway socket.
|
||||
*
|
||||
* - ** `"Failed to connect to voice: VOICE_SESSION_DESCRIPTION timed out"` **
|
||||
*
|
||||
* - ** `"Voice transport timed out"` **
|
||||
*
|
||||
* - ** `"Connected from another location"` **
|
||||
*
|
||||
* - ** `"Kicked from the voice channel"` **
|
||||
*
|
||||
* Set when server kicks the user from a voice channel,
|
||||
* user accounts do not support botapi multiserver voice.
|
||||
*
|
||||
* - ** `"Changing server"` **
|
||||
*
|
||||
* - ** `"Guild unavailable"` **
|
||||
*
|
||||
* This event fires before `GUILD_UNAVAILABLE`.
|
||||
*
|
||||
* - ** `"Call unavailable"` **
|
||||
*
|
||||
* - ** `"Session has been invalidated"` **
|
||||
*
|
||||
* Set when the gateway connection could not be resumed and new
|
||||
* session has been started. Fires for all previously active voice
|
||||
* connections.
|
||||
*
|
||||
* - ** `"Manual disconnect"` **
|
||||
*
|
||||
* Set if `channel.leave()` or `client.disconnect()` was called.
|
||||
* Will also be set if channel or guild gets deleted (`VOICE_DISCONNECTED`
|
||||
* emits before `GUILD_DELETE` or `CHANNEL_DELETE` respectively).
|
||||
*
|
||||
* If Discord decides to change voice servers - check if `endpointAwait`
|
||||
* is not null and contains a `Promise` which will resolve when a new
|
||||
* connection is fully initialized (`VOICE_CONNECTED` will also fire)
|
||||
* and reject if reconnect fails.
|
||||
*
|
||||
* Calls on `.join()` for channels of the same guild will return the same
|
||||
* promise.
|
||||
*
|
||||
* Call `.leave()` on pending connection's channel to cancel a reconnect.
|
||||
* Pending promise (`endpointAwait`) will be rejected with
|
||||
* `Error` message "Cancelled".
|
||||
*
|
||||
* If a gateway disconnects, pending connections that belong to the gateway
|
||||
* will be rejected with `Error` message `"Gateway disconnected"`.
|
||||
*
|
||||
* @event VOICE_DISCONNECTED
|
||||
* @property {VoiceSocket} socket
|
||||
* @property {IVoiceConnection} voiceConnection
|
||||
* @property {Error|null} error
|
||||
* @property {boolean} manual
|
||||
* Indicating whether was caused by `IVoiceChannel.leave()` or
|
||||
* `Discordie.disconnect()`, also true if channel/guild has been deleted
|
||||
* @property {Promise<VoiceConnectionInfo, Error|Number>} endpointAwait
|
||||
* Indicates whether there is a reconnect pending, reconnects can occur when
|
||||
* Discord decides to move users to another voice server
|
||||
* @example
|
||||
* client.Dispatcher.on("VOICE_DISCONNECTED", e => {
|
||||
* const channel = e.voiceConnection.channel;
|
||||
* if (!channel) return console.log("Channel has been deleted");
|
||||
*
|
||||
* if (e.endpointAwait) {
|
||||
* // handle reconnect instantly if it's a server-switch disconnect
|
||||
* // transparently creates same promise as `oldChannel.join()`
|
||||
* // see the `reconnect` function below
|
||||
*
|
||||
* // Note: During Discord outages it will act like the official client
|
||||
* // and wait for an endpoint. Sometimes this can take a very
|
||||
* // long time. To cancel pending reconnect just call leave on
|
||||
* // the voice channel. Pending promise will reject with
|
||||
* // `Error` message "Cancelled".
|
||||
*
|
||||
*
|
||||
* e.endpointAwait
|
||||
* .then(info => onConnected(info))
|
||||
* .catch(err => {
|
||||
* // server switching failed, do a regular backoff
|
||||
* setTimeout(() => reconnect(channel), 5000);
|
||||
* });
|
||||
* return;
|
||||
* }
|
||||
*
|
||||
* // normal disconnect
|
||||
* setTimeout(() => reconnect(channel), 5000);
|
||||
* });
|
||||
* function reconnect(channel) {
|
||||
* var channelName = channel.name;
|
||||
* channel.join()
|
||||
* .then(info => onConnected(info))
|
||||
* .catch(err => console.log("Failed to connect to " + channelName));
|
||||
* // this example will stop reconnecting after 1 attempt
|
||||
* // you can continue trying to reconnect
|
||||
* }
|
||||
* function onConnected(info) {
|
||||
* console.log("Connected to " + info.voiceConnection.channel.name);
|
||||
* }
|
||||
*/
|
||||
VOICE_DISCONNECTED: 0,
|
||||
|
||||
/**
|
||||
* Emitted when guild becomes unavailable.
|
||||
* Guild is deleted from cache until another `GUILD_CREATE`.
|
||||
* @event GUILD_UNAVAILABLE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {String} guildId
|
||||
*/
|
||||
GUILD_UNAVAILABLE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when call becomes unavailable.
|
||||
* @event CALL_UNAVAILABLE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {String} channelId
|
||||
*/
|
||||
CALL_UNAVAILABLE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when current user is being rung in a call.
|
||||
* @event CALL_RING
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IDirectMessageChannel} channel
|
||||
*/
|
||||
CALL_RING: 0,
|
||||
|
||||
/**
|
||||
* Emitted when `username`, `avatar` or `discriminator` difference detected
|
||||
* in an incoming `PRESENCE_UPDATE` event.
|
||||
* @event PRESENCE_MEMBER_INFO_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {Object} old - Old instance of internal User model (immutable)
|
||||
* @property {Object} new - New instance of internal User model (immutable)
|
||||
*/
|
||||
PRESENCE_MEMBER_INFO_UPDATE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when user leaves voice channel.
|
||||
* Fields `newChannelId`/`newGuildId` contain ids that will appear in
|
||||
* `VOICE_CHANNEL_JOIN` event that will follow if user has moved to
|
||||
* another channel, otherwise null.
|
||||
* @event VOICE_CHANNEL_LEAVE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser} user
|
||||
* @property {IChannel|null} channel
|
||||
* @property {String} channelId
|
||||
* @property {String} guildId
|
||||
* @property {String|null} newChannelId -
|
||||
* Next channel id if user moved to another channel
|
||||
* @property {String|null} newGuildId -
|
||||
* Next guild id if user moved to another channel
|
||||
*/
|
||||
VOICE_CHANNEL_LEAVE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when user joins voice channel.
|
||||
* @event VOICE_CHANNEL_JOIN
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser} user
|
||||
* @property {IChannel} channel
|
||||
* @property {String} channelId
|
||||
* @property {String} guildId
|
||||
*/
|
||||
VOICE_CHANNEL_JOIN: 0,
|
||||
|
||||
/**
|
||||
* Emitted when user self mute change is detected.
|
||||
* Manual client-side mute.
|
||||
* @event VOICE_USER_SELF_MUTE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser} user
|
||||
* @property {IChannel} channel
|
||||
* @property {String} channelId
|
||||
* @property {String} guildId
|
||||
* @property {boolean} state - Current state (is self muted)
|
||||
*/
|
||||
VOICE_USER_SELF_MUTE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when user self deaf change is detected.
|
||||
* Manual client-side deafen.
|
||||
* @event VOICE_USER_SELF_DEAF
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser} user
|
||||
* @property {IChannel} channel
|
||||
* @property {String} channelId
|
||||
* @property {String} guildId
|
||||
* @property {boolean} state - Current state (is self deafened)
|
||||
*/
|
||||
VOICE_USER_SELF_DEAF: 0,
|
||||
|
||||
/**
|
||||
* Emitted when user mute change is detected.
|
||||
* Global server-side mute.
|
||||
* @event VOICE_USER_MUTE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser} user
|
||||
* @property {IChannel} channel
|
||||
* @property {String} channelId
|
||||
* @property {String} guildId
|
||||
* @property {boolean} state - Current state (is muted globally)
|
||||
*/
|
||||
VOICE_USER_MUTE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when user deaf change is detected.
|
||||
* Global server-side deafen.
|
||||
* @event VOICE_USER_DEAF
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser} user
|
||||
* @property {IChannel} channel
|
||||
* @property {String} channelId
|
||||
* @property {String} guildId
|
||||
* @property {boolean} state - Current state (is deafened globally)
|
||||
*/
|
||||
VOICE_USER_DEAF: 0,
|
||||
|
||||
// ============================= PROXY EVENTS =============================
|
||||
/**
|
||||
* @event MESSAGE_CREATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IMessage} message
|
||||
*/
|
||||
MESSAGE_CREATE: 0,
|
||||
/**
|
||||
* Emitted when user deletes their message.
|
||||
* Contains null `message` if not cached.
|
||||
* @event MESSAGE_DELETE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {String} channelId
|
||||
* @property {String} messageId
|
||||
* @property {IMessage|null} message
|
||||
*/
|
||||
MESSAGE_DELETE: 0,
|
||||
/**
|
||||
* Emitted when a bot deletes more than 1 message at once.
|
||||
* @event MESSAGE_DELETE_BULK
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {String} channelId
|
||||
* @property {Array<String>} messageIds
|
||||
* @property {Array<IMessage>} messages
|
||||
* Array of known deleted messages, can be empty
|
||||
*/
|
||||
MESSAGE_DELETE_BULK: 0,
|
||||
/**
|
||||
* Emitted when user updates their message.
|
||||
* Contains null `message` if not cached.
|
||||
* @event MESSAGE_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IMessage|null} message
|
||||
* @property {Object} data - Raw message object received from server
|
||||
*/
|
||||
MESSAGE_UPDATE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when on changes for username, avatar, status or game.
|
||||
*
|
||||
* Emitted multiple times for each shared guild with the local user and the
|
||||
* user presence is for.
|
||||
*
|
||||
* Compare `user.status` and `user.previousStatus` to detect status changes.
|
||||
*
|
||||
* Games can be checked with `user.game` and `user.previousGame`
|
||||
* (and helpers for names `user.gameName` and `user.previousGameName`)
|
||||
* respectively.
|
||||
*
|
||||
* > **Note:** Property `member` will contain `IUser` instance if user
|
||||
* > has left the `guild`.
|
||||
*
|
||||
* @event PRESENCE_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IUser} user
|
||||
* @property {IGuildMember|IUser} member
|
||||
*/
|
||||
PRESENCE_UPDATE: 0,
|
||||
/**
|
||||
* @event TYPING_START
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser} user
|
||||
* @property {Number} timestamp - Unix timestamp
|
||||
* @property {IChannel} channel
|
||||
*/
|
||||
TYPING_START: 0,
|
||||
|
||||
/**
|
||||
* @event CHANNEL_CREATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IChannel} channel
|
||||
*/
|
||||
CHANNEL_CREATE: 0,
|
||||
/**
|
||||
* @event CHANNEL_DELETE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {String} channelId
|
||||
* @property {Object} data - Raw channel object received from server
|
||||
*/
|
||||
CHANNEL_DELETE: 0,
|
||||
/**
|
||||
* @event CHANNEL_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IChannel} channel
|
||||
* @property {Function} getChanges
|
||||
* Function returning an object `{before: ..., after: ...}` containing two
|
||||
* raw channel objects.
|
||||
*/
|
||||
CHANNEL_UPDATE: 0,
|
||||
/**
|
||||
* Emitted when a user has been added to a group dm.
|
||||
* @event CHANNEL_RECIPIENT_ADD
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IDirectMessageChannel} channel
|
||||
* @property {IUser} user
|
||||
*/
|
||||
CHANNEL_RECIPIENT_ADD: 0,
|
||||
/**
|
||||
* Emitted when a user has been removed or left from a group dm.
|
||||
* @event CHANNEL_RECIPIENT_REMOVE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IDirectMessageChannel} channel
|
||||
* @property {IUser} user
|
||||
*/
|
||||
CHANNEL_RECIPIENT_REMOVE: 0,
|
||||
|
||||
/**
|
||||
* @event GUILD_CREATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {boolean} becameAvailable
|
||||
* Indicates whether the guild has recovered from unavailable state
|
||||
*/
|
||||
GUILD_CREATE: 0,
|
||||
/**
|
||||
* @event GUILD_DELETE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {String} guildId
|
||||
* @property {Object} data - Raw guild object received from server
|
||||
* @property {Function} getCachedData
|
||||
* Function returning a raw guild object or null.
|
||||
*/
|
||||
GUILD_DELETE: 0,
|
||||
/**
|
||||
* @event GUILD_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {Function} getChanges
|
||||
* Function returning an object `{before: ..., after: ...}` containing two
|
||||
* raw guild objects.
|
||||
*/
|
||||
GUILD_UPDATE: 0,
|
||||
|
||||
/**
|
||||
* @event GUILD_MEMBER_ADD
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IGuildMember} member
|
||||
*/
|
||||
GUILD_MEMBER_ADD: 0,
|
||||
/**
|
||||
* Emitted when any other member of a joined guild leaves,
|
||||
* events for self are blocked internally due to race condition between
|
||||
* `GUILD_DELETE` and `GUILD_MEMBER_REMOVE`.
|
||||
* @event GUILD_MEMBER_REMOVE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IUser} user
|
||||
* @property {Object} data - Raw data received from server
|
||||
* @property {Function} getCachedData
|
||||
* Function returning a raw member object or null.
|
||||
*/
|
||||
GUILD_MEMBER_REMOVE: 0,
|
||||
/**
|
||||
* @event GUILD_MEMBER_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IGuildMember} member
|
||||
* @property {Array<IRole>} rolesAdded
|
||||
* @property {Array<IRole>} rolesRemoved
|
||||
* @property {String|null} previousNick
|
||||
* @property {Function} getChanges
|
||||
* Function returning an object `{before: ..., after: ...}` containing two
|
||||
* raw member objects.
|
||||
*/
|
||||
GUILD_MEMBER_UPDATE: 0,
|
||||
|
||||
/**
|
||||
* @event GUILD_BAN_ADD
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IUser} user
|
||||
*/
|
||||
GUILD_BAN_ADD: 0,
|
||||
/**
|
||||
* @event GUILD_BAN_REMOVE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IUser} user
|
||||
*/
|
||||
GUILD_BAN_REMOVE: 0,
|
||||
|
||||
/**
|
||||
* @event GUILD_ROLE_CREATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IRole} role
|
||||
*/
|
||||
GUILD_ROLE_CREATE: 0,
|
||||
/**
|
||||
* @event GUILD_ROLE_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IRole} role
|
||||
* @property {Function} getChanges
|
||||
* Function returning an object `{before: ..., after: ...}` containing two
|
||||
* raw role objects.
|
||||
*/
|
||||
GUILD_ROLE_UPDATE: 0,
|
||||
/**
|
||||
* @event GUILD_ROLE_DELETE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {String} roleId
|
||||
* @property {Function} getCachedData
|
||||
* Function returning a raw role object or null.
|
||||
*/
|
||||
GUILD_ROLE_DELETE: 0,
|
||||
|
||||
/**
|
||||
* @event GUILD_EMOJIS_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {Function} getChanges
|
||||
* Function returning an object `{before: ..., after: ...}` containing two
|
||||
* full emoji arrays in format provided by Discord.
|
||||
*/
|
||||
GUILD_EMOJIS_UPDATE: 0,
|
||||
|
||||
/**
|
||||
* @event CALL_CREATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IDirectMessageChannel} channel
|
||||
* @property {ICall} call
|
||||
*/
|
||||
CALL_CREATE: 0,
|
||||
/**
|
||||
* @event CALL_DELETE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {String} channelId
|
||||
* @property {Object} data - Raw object received from server
|
||||
*/
|
||||
CALL_DELETE: 0,
|
||||
/**
|
||||
* @event CALL_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IDirectMessageChannel} channel
|
||||
* @property {ICall} call
|
||||
*/
|
||||
CALL_UPDATE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when a webhook is updated.
|
||||
* @event WEBHOOKS_UPDATE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IGuild} guild
|
||||
* @property {IChannel} channel
|
||||
* @property {Object} data - Raw object received from server
|
||||
*/
|
||||
WEBHOOKS_UPDATE: 0,
|
||||
|
||||
/**
|
||||
* Emitted when a reaction is added to a message.
|
||||
* @event MESSAGE_REACTION_ADD
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser|null} user
|
||||
* @property {IChannel|null} channel
|
||||
* @property {IMessage|null} message
|
||||
* @property {Object} emoji
|
||||
* Partial emoji `{id: String|null, name: String}`
|
||||
* @property {Object} data - Raw object received from server
|
||||
*/
|
||||
MESSAGE_REACTION_ADD: 0,
|
||||
/**
|
||||
* Emitted when a reaction is removed from a message.
|
||||
* @event MESSAGE_REACTION_REMOVE
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IUser|null} user
|
||||
* @property {IChannel|null} channel
|
||||
* @property {IMessage|null} message
|
||||
* @property {Object} emoji
|
||||
* Partial emoji `{id: String|null, name: String}`
|
||||
* @property {Object} data - Raw object received from server
|
||||
*/
|
||||
MESSAGE_REACTION_REMOVE: 0,
|
||||
/**
|
||||
* Emitted when message reactions are cleared.
|
||||
* @event MESSAGE_REACTION_REMOVE_ALL
|
||||
* @property {GatewaySocket} socket
|
||||
* @property {IChannel|null} channel
|
||||
* @property {IMessage|null} message
|
||||
* @property {Object} data - Raw object received from server
|
||||
* @property {Function} getCachedData
|
||||
* Function returning an array of removed reactions or null.
|
||||
*/
|
||||
MESSAGE_REACTION_REMOVE_ALL: 0,
|
||||
},
|
||||
ChannelTypes: {
|
||||
GUILD_TEXT: 0,
|
||||
DM: 1,
|
||||
GUILD_VOICE: 2,
|
||||
GROUP_DM: 3
|
||||
},
|
||||
MessageTypes: {
|
||||
DEFAULT: 0,
|
||||
RECIPIENT_ADD: 1,
|
||||
RECIPIENT_REMOVE: 2,
|
||||
CALL: 3,
|
||||
CHANNEL_NAME_CHANGE: 4,
|
||||
CHANNEL_ICON_CHANGE: 5,
|
||||
CHANNEL_PINNED_MESSAGE: 6
|
||||
},
|
||||
EncryptionModes: {
|
||||
plain: 0,
|
||||
xsalsa20_poly1305: 0,
|
||||
},
|
||||
|
||||
ME: "@me",
|
||||
Endpoints: {
|
||||
CDN_AVATAR: (userId, hash, format) => `/avatars/${userId}/${hash}.${format || "jpg"}`,
|
||||
CDN_DM_ICON: (channelId, hash) => `/channel-icons/${channelId}/${hash}.jpg`,
|
||||
CDN_GUILD_ICON: (guildId, hash) => `/icons/${guildId}/${hash}.jpg`,
|
||||
CDN_GUILD_SPLASH: (guildId, hash) => `/splashes/${guildId}/${hash}.jpg`,
|
||||
CDN_EMOJI: emojiId => `/emojis/${emojiId}.png`,
|
||||
LOGIN: "/auth/login",
|
||||
ME: "/users/@me",
|
||||
TYPING: channelId => `/channels/${channelId}/typing`,
|
||||
CHANNEL_PERMISSIONS: channelId => `/channels/${channelId}/permissions`,
|
||||
CHANNEL_RECIPIENTS: channelId => `/channels/${channelId}/recipients`,
|
||||
CHANNEL_WEBHOOKS: channelId => `/channels/${channelId}/webhooks`,
|
||||
MESSAGES: channelId => `/channels/${channelId}/messages`,
|
||||
PINS: channelId => `/channels/${channelId}/pins`,
|
||||
CHANNELS: "/channels",
|
||||
SETTINGS: "/users/@me/settings",
|
||||
GUILD_CHANNELS: guildId => `/guilds/${guildId}/channels`,
|
||||
GUILDS: "/guilds",
|
||||
INSTANT_INVITES: channelId => `/channels/${channelId}/invites`,
|
||||
CALL: channelId => `/channels/${channelId}/call`,
|
||||
CALL_RING: channelId => `/channels/${channelId}/call/ring`,
|
||||
CALL_STOP_RINGING: channelId => `/channels/${channelId}/call/stop-ringing`,
|
||||
|
||||
REACTIONS: (channelId, messageId) =>
|
||||
`/channels/${channelId}/messages/${messageId}/reactions`,
|
||||
REACTIONS_EMOJI: (channelId, messageId, emoji) =>
|
||||
`/channels/${channelId}/messages/${messageId}/reactions/${emoji}`,
|
||||
REACTION: (channelId, messageId, emoji, userId) =>
|
||||
`/channels/${channelId}/messages/${messageId}/reactions/${emoji}/${userId}`,
|
||||
|
||||
USER_CHANNELS: userId => `/users/${userId}/channels`,
|
||||
GUILD_MEMBERS: guildId => `/guilds/${guildId}/members`,
|
||||
GUILD_BANS: guildId => `/guilds/${guildId}/bans`,
|
||||
GUILD_ROLES: guildId => `/guilds/${guildId}/roles`,
|
||||
GUILD_INSTANT_INVITES: guildId => `/guilds/${guildId}/invites`,
|
||||
GUILD_EMBED: guildId => `/guilds/${guildId}/embed`,
|
||||
GUILD_PRUNE: guildId => `/guilds/${guildId}/prune`,
|
||||
GUILD_REGIONS: guildId => `/guilds/${guildId}/regions`,
|
||||
GUILD_EMOJIS: guildId => `/guilds/${guildId}/emojis`,
|
||||
GUILD_EMOJI: (guildId, emojiId) => `/guilds/${guildId}/emojis/${emojiId}`,
|
||||
GUILD_WEBHOOKS: guildId => `/guilds/${guildId}/webhooks`,
|
||||
WEBHOOK: webhookId => `/webhooks/${webhookId}`,
|
||||
USERS: "/users",
|
||||
LOGOUT: "/auth/logout",
|
||||
REGISTER: "/auth/register",
|
||||
INVITE: "/invite",
|
||||
REGIONS: "/voice/regions",
|
||||
ICE: "/voice/ice",
|
||||
GATEWAY: "/gateway",
|
||||
|
||||
OAUTH2_APPLICATION: id => `/oauth2/applications/${id}`
|
||||
},
|
||||
API_VERSION: 6,
|
||||
get API_ENDPOINT() {
|
||||
return "https://discordapp.com/api/v" + this.API_VERSION;
|
||||
},
|
||||
CDN_ENDPOINT: "https://cdn.discordapp.com",
|
||||
|
||||
Permissions: Permissions,
|
||||
PermissionsDefault: PermissionsDefault,
|
||||
PermissionSpecs: PermissionSpecs,
|
||||
|
||||
StatusTypes: {
|
||||
ONLINE: "online",
|
||||
OFFLINE: "offline",
|
||||
IDLE: "idle",
|
||||
DND: "dnd",
|
||||
INVISIBLE: "invisible"
|
||||
},
|
||||
|
||||
ActivityTypes: {
|
||||
PLAYING: 0,
|
||||
STREAMING: 1
|
||||
},
|
||||
|
||||
VerificationLevel: {
|
||||
NONE: 0,
|
||||
LOW: 1,
|
||||
MEDIUM: 2,
|
||||
HIGH: 3
|
||||
},
|
||||
|
||||
MFALevels: {
|
||||
NONE: 0,
|
||||
ELEVATED: 1
|
||||
},
|
||||
|
||||
UserNotificationSettings: {
|
||||
ALL_MESSAGES: 0,
|
||||
ONLY_MENTIONS: 1,
|
||||
NO_MESSAGES: 2,
|
||||
NULL: 3
|
||||
},
|
||||
|
||||
TYPING_TIMEOUT: 10000,
|
||||
|
||||
BITRATE_MIN: 8000,
|
||||
BITRATE_DEFAULT: 64000,
|
||||
BITRATE_MAX: 96000,
|
||||
BITRATE_MAX_VIP: 128000,
|
||||
|
||||
DISCORD_SAMPLE_RATE: 48000,
|
||||
|
||||
NON_USER_BOT_DISCRIMINATOR: "0000"
|
||||
};
|
||||
|
||||
function mirror(d) { Object.keys(d).forEach((k) => d[k] = k); }
|
||||
function enumerate(d) { let c = 0; Object.keys(d).forEach((k) => d[k] = c++); }
|
||||
|
||||
mirror(Constants.Events);
|
||||
mirror(Constants.EncryptionModes);
|
||||
mirror(Constants.DiscordieState);
|
||||
|
||||
module.exports = Constants;
|
12
node_modules/discordie/lib/collections/BaseArrayCollection.js
generated
vendored
Normal file
12
node_modules/discordie/lib/collections/BaseArrayCollection.js
generated
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
"use strict";
|
||||
|
||||
class BaseArrayCollection extends Array {
|
||||
// avoid constructor, calling array mutation methods will call it (ES2015)
|
||||
static create() {
|
||||
const instance = new this();
|
||||
this._constructor.apply(instance, arguments);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BaseArrayCollection;
|
19
node_modules/discordie/lib/collections/BaseCollection.js
generated
vendored
Normal file
19
node_modules/discordie/lib/collections/BaseCollection.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
const BaseModel = require("../models/BaseModel");
|
||||
|
||||
class BaseCollection extends Map {
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
mergeOrSet(key, value) {
|
||||
const old = this.get(key);
|
||||
let merged = value;
|
||||
if (old && old instanceof BaseModel) {
|
||||
merged = old.merge(value);
|
||||
}
|
||||
this.set(key, merged);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BaseCollection;
|
97
node_modules/discordie/lib/collections/CallCollection.js
generated
vendored
Normal file
97
node_modules/discordie/lib/collections/CallCollection.js
generated
vendored
Normal file
@ -0,0 +1,97 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseCollection = require("./BaseCollection");
|
||||
|
||||
const Call = require("../models/Call");
|
||||
|
||||
function emitRing(gw, channelId) {
|
||||
const channel = this._discordie.DirectMessageChannels.get(channelId);
|
||||
if (!channel) return;
|
||||
|
||||
this._discordie.Dispatcher.emit(Events.CALL_RING, {
|
||||
socket: gw,
|
||||
channel: channel
|
||||
});
|
||||
}
|
||||
|
||||
function checkRing(gw, prev, next) {
|
||||
const channelId = next.channel_id;
|
||||
const userId = this._discordie._user && this._discordie._user.id;
|
||||
if (!channelId || !userId) return;
|
||||
if (!next || !next.ringing) return;
|
||||
|
||||
const hasPrev = prev ? prev.ringing.indexOf(userId) >= 0 : false;
|
||||
const hasNext = next.ringing.indexOf(userId) >= 0;
|
||||
|
||||
if (!hasPrev && hasNext) emitRing.call(this, gw, channelId);
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data) {
|
||||
this.clear();
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleCallCreate(call, e) {
|
||||
this.set(call.channel_id, new Call(call));
|
||||
checkRing.call(this, e.socket, null, call);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleCallUpdate(call, e) {
|
||||
const prev = this.get(call.channel_id);
|
||||
this.mergeOrSet(call.channel_id, new Call(call));
|
||||
checkRing.call(this, e.socket, prev, call);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleCallDelete(call) {
|
||||
const _call = this.get(call.channel_id);
|
||||
if (!_call) return true;
|
||||
|
||||
if (call.unavailable === true) {
|
||||
this.mergeOrSet(call.channel_id, {unavailable: true});
|
||||
} else {
|
||||
this.delete(call.channel_id);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class CallCollection extends BaseCollection {
|
||||
constructor(discordie, gateway) {
|
||||
super();
|
||||
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
CALL_CREATE: handleCallCreate,
|
||||
CALL_UPDATE: handleCallUpdate,
|
||||
CALL_DELETE: handleCallDelete
|
||||
});
|
||||
});
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
isActive(channelId, messageId) {
|
||||
const call = this.get(channelId);
|
||||
if (messageId) {
|
||||
return call && !call.unavailable && call.message_id == messageId;
|
||||
}
|
||||
return call && !call.unavailable;
|
||||
}
|
||||
isUnavailable(channelId) {
|
||||
const call = this.get(channelId);
|
||||
return call && call.unavailable;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CallCollection;
|
193
node_modules/discordie/lib/collections/ChannelCollection.js
generated
vendored
Normal file
193
node_modules/discordie/lib/collections/ChannelCollection.js
generated
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const ChannelTypes = Constants.ChannelTypes;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseCollection = require("./BaseCollection");
|
||||
|
||||
const Channel = require("../models/Channel");
|
||||
const PermissionOverwrite = require("../models/PermissionOverwrite");
|
||||
const IPermissions = require("../interfaces/IPermissions");
|
||||
|
||||
function convertOverwrites(channel) {
|
||||
const overwrites = channel.permission_overwrites || [];
|
||||
|
||||
// note: @everyone overwrite does not exist by default
|
||||
// this will add one locally
|
||||
if (channel.guild_id) {
|
||||
const everyone = overwrites.find(o => o.id == channel.guild_id);
|
||||
if (!everyone) {
|
||||
overwrites.push({
|
||||
id: channel.guild_id,
|
||||
type: "role",
|
||||
allow: IPermissions.NONE,
|
||||
deny: IPermissions.NONE
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return overwrites.map(o => new PermissionOverwrite(o));
|
||||
}
|
||||
|
||||
function createChannel(channel) {
|
||||
const channelRecipients =
|
||||
Array.isArray(channel.recipients) ? channel.recipients.map(r => r.id) : [];
|
||||
|
||||
return new Channel({
|
||||
id: channel.id,
|
||||
type: channel.type || ChannelTypes.GUILD_TEXT,
|
||||
name: channel.name || "",
|
||||
topic: channel.topic || "",
|
||||
position: channel.position || 0,
|
||||
recipients: new Set(channelRecipients),
|
||||
guild_id: channel.guild_id || null,
|
||||
permission_overwrites: convertOverwrites(channel),
|
||||
bitrate: channel.bitrate || Constants.BITRATE_DEFAULT,
|
||||
user_limit: channel.user_limit || 0,
|
||||
owner_id: channel.owner_id || null,
|
||||
icon: channel.icon || null
|
||||
});
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data) {
|
||||
this.clear();
|
||||
data.guilds.forEach(guild => handleGuildCreate.call(this, guild));
|
||||
data.private_channels.forEach(channel => {
|
||||
this.set(channel.id, createChannel(channel));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleCreateOrUpdateChannel(channel, e) {
|
||||
const prev = this.get(channel.id);
|
||||
const next = createChannel(channel);
|
||||
this.mergeOrSet(channel.id, next);
|
||||
if (e.type === Events.CHANNEL_UPDATE) {
|
||||
e.data._prev = prev;
|
||||
e.data._next = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleChannelDelete(channel) {
|
||||
this.delete(channel.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildCreate(guild) {
|
||||
if (!guild || guild.unavailable) return true;
|
||||
|
||||
guild.channels.forEach(channel => {
|
||||
channel.guild_id = guild.id;
|
||||
this.set(channel.id, createChannel(channel));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildDelete(guild) {
|
||||
this.forEach((channel, id) => {
|
||||
if (channel.guild_id == guild.id)
|
||||
this.delete(id);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function processRecipientAddOrRemove(data, handler) {
|
||||
const user = data.user;
|
||||
const channel = this.get(data.channel_id);
|
||||
if (!channel) return;
|
||||
if (!this._discordie._user || this._discordie._user.id == user.id) return;
|
||||
handler(channel, user);
|
||||
}
|
||||
|
||||
function handleRecipientAdd(data) {
|
||||
const handler = (channel, user) => channel.recipients.add(user.id);
|
||||
processRecipientAddOrRemove.call(this, data, handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleRecipientRemove(data) {
|
||||
const handler = (channel, user) => channel.recipients.delete(user.id);
|
||||
processRecipientAddOrRemove.call(this, data, handler);
|
||||
return true;
|
||||
}
|
||||
|
||||
class ChannelCollection extends BaseCollection {
|
||||
constructor(discordie, gateway) {
|
||||
super();
|
||||
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
GUILD_CREATE: handleGuildCreate,
|
||||
GUILD_DELETE: handleGuildDelete,
|
||||
CHANNEL_CREATE: handleCreateOrUpdateChannel,
|
||||
CHANNEL_UPDATE: handleCreateOrUpdateChannel,
|
||||
CHANNEL_DELETE: handleChannelDelete,
|
||||
CHANNEL_RECIPIENT_ADD: handleRecipientAdd,
|
||||
CHANNEL_RECIPIENT_REMOVE: handleRecipientRemove
|
||||
});
|
||||
});
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
*getPrivateChannelIterator() {
|
||||
for (let channel of this.values()) {
|
||||
if (this._isPrivate(channel))
|
||||
yield channel;
|
||||
}
|
||||
}
|
||||
*getGuildChannelIterator() {
|
||||
for (let channel of this.values()) {
|
||||
if (!this._isPrivate(channel))
|
||||
yield channel;
|
||||
}
|
||||
}
|
||||
getPrivateChannel(channelId) {
|
||||
var channel = this.get(channelId);
|
||||
if (!channel) return null;
|
||||
return this._isPrivate(channel) ? channel : null;
|
||||
}
|
||||
getGuildChannel(channelId) {
|
||||
var channel = this.get(channelId);
|
||||
if (!channel) return null;
|
||||
return !this._isPrivate(channel) ? channel : null;
|
||||
}
|
||||
isPrivate(channelId) {
|
||||
const channel = this.get(channelId);
|
||||
if (channel)
|
||||
return this._isPrivate(channel);
|
||||
return null;
|
||||
}
|
||||
_isPrivate(channel) {
|
||||
const type = channel.type;
|
||||
return (type === ChannelTypes.DM || type === ChannelTypes.GROUP_DM);
|
||||
}
|
||||
getChannelType(channelId) {
|
||||
const channel = this.get(channelId);
|
||||
if (channel) return channel.type;
|
||||
return null;
|
||||
}
|
||||
update(channel) {
|
||||
handleCreateOrUpdateChannel.call(this, channel, {});
|
||||
}
|
||||
updatePermissionOverwrite(channelId, overwrite) {
|
||||
const channel = this.get(channelId);
|
||||
if (!channel) return;
|
||||
const newOverwrites = channel.permission_overwrites
|
||||
.filter(o => o.id != overwrite.id && o.type != overwrite.type);
|
||||
newOverwrites.push(new PermissionOverwrite(overwrite));
|
||||
this.set(channelId, channel.merge({
|
||||
permission_overwrites: newOverwrites
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChannelCollection;
|
183
node_modules/discordie/lib/collections/GuildCollection.js
generated
vendored
Normal file
183
node_modules/discordie/lib/collections/GuildCollection.js
generated
vendored
Normal file
@ -0,0 +1,183 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseCollection = require("./BaseCollection");
|
||||
|
||||
const MFALevels = Constants.MFALevels;
|
||||
const VerificationLevel = Constants.VerificationLevel;
|
||||
const UserNotificationSettings = Constants.UserNotificationSettings;
|
||||
|
||||
const Guild = require("../models/Guild");
|
||||
const Role = require("../models/Role");
|
||||
|
||||
function convertRoles(roles) {
|
||||
const map = new Map();
|
||||
roles.forEach(role => {
|
||||
map.set(role.id, new Role(role));
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
function createGuild(guild, old) {
|
||||
return new Guild({
|
||||
id: guild.id,
|
||||
name: guild.name,
|
||||
region: guild.region,
|
||||
icon: guild.icon,
|
||||
splash: guild.splash,
|
||||
features: new Set(guild.features),
|
||||
emojis: (guild.emojis != null ? guild.emojis : old.emojis) || [],
|
||||
default_message_notifications:
|
||||
guild.default_message_notifications ||
|
||||
UserNotificationSettings.ALL_MESSAGES,
|
||||
owner_id: guild.owner_id,
|
||||
roles: convertRoles(guild.roles),
|
||||
afk_channel_id: guild.afk_channel_id,
|
||||
afk_timeout: guild.afk_timeout,
|
||||
verification_level: guild.verification_level || VerificationLevel.NONE,
|
||||
member_count:
|
||||
(guild.member_count != null ? guild.member_count : old.member_count),
|
||||
large: (guild.large != null ? guild.large : old.large) || false,
|
||||
mfa_level: guild.mfa_level || MFALevels.NONE,
|
||||
joined_at: guild.joined_at || old.joined_at
|
||||
});
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data) {
|
||||
this.clear();
|
||||
data.guilds.forEach(guild => {
|
||||
if (guild.unavailable) return;
|
||||
this.set(guild.id, createGuild(guild, {}));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleCreateOrUpdateGuild(guild, e) {
|
||||
if (!guild || guild.unavailable) return true;
|
||||
const prev = this.get(guild.id) || {};
|
||||
const next = createGuild(guild, prev);
|
||||
this.mergeOrSet(guild.id, next);
|
||||
if (e.type === Events.GUILD_UPDATE) {
|
||||
e.data._prev = prev;
|
||||
e.data._next = next;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleDeleteGuild(guild, e) {
|
||||
const oldGuild = this.get(guild.id);
|
||||
if (oldGuild) e.data._cached = oldGuild;
|
||||
|
||||
this.delete(guild.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildSync(guild) {
|
||||
let oldGuild = this.get(guild.id);
|
||||
if (!oldGuild) return true;
|
||||
this.mergeOrSet(guild.id, {
|
||||
large: (guild.large != null ? guild.large : oldGuild.large)
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildRoleCreateOrUpdate(data, e) {
|
||||
let guild = this.get(data.guild_id);
|
||||
if (guild) {
|
||||
const prev = guild.roles.get(data.role.id);
|
||||
const next = new Role(data.role);
|
||||
guild.roles.set(data.role.id, next);
|
||||
if (e.type === Events.GUILD_ROLE_UPDATE) {
|
||||
e.data._prev = prev;
|
||||
e.data._next = next;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildRoleDelete(data, e) {
|
||||
let guild = this.get(data.guild_id);
|
||||
if (guild) {
|
||||
const oldRole = guild.roles.get(data.role_id);
|
||||
if (oldRole) e.data._cached = oldRole;
|
||||
|
||||
guild.roles.delete(data.role_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildMemberAdd(member) {
|
||||
updateMemberCount.call(this, member.guild_id, +1);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildMemberRemove(member) {
|
||||
updateMemberCount.call(this, member.guild_id, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
function updateMemberCount(guildId, delta) {
|
||||
let guild = this.get(guildId);
|
||||
if (!guild) return true;
|
||||
this.mergeOrSet(guildId, { member_count: guild.member_count + delta });
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildEmojisUpdate(data, e) {
|
||||
if (!data || data.emojis == null) return true;
|
||||
|
||||
let guild = this.get(data.guild_id);
|
||||
if (!guild) return true;
|
||||
|
||||
const prev = guild.emojis;
|
||||
const next = data.emojis;
|
||||
this.mergeOrSet(data.guild_id, { emojis: data.emojis });
|
||||
if (e.type === Events.GUILD_EMOJIS_UPDATE) {
|
||||
e.data._prev = prev;
|
||||
e.data._next = next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class GuildCollection extends BaseCollection {
|
||||
constructor(discordie, gateway) {
|
||||
super();
|
||||
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
GUILD_SYNC: handleGuildSync,
|
||||
GUILD_CREATE: handleCreateOrUpdateGuild,
|
||||
GUILD_UPDATE: handleCreateOrUpdateGuild,
|
||||
GUILD_DELETE: handleDeleteGuild,
|
||||
GUILD_ROLE_CREATE: handleGuildRoleCreateOrUpdate,
|
||||
GUILD_ROLE_UPDATE: handleGuildRoleCreateOrUpdate,
|
||||
GUILD_ROLE_DELETE: handleGuildRoleDelete,
|
||||
GUILD_MEMBER_ADD: handleGuildMemberAdd,
|
||||
GUILD_MEMBER_REMOVE: handleGuildMemberRemove,
|
||||
GUILD_EMOJIS_UPDATE: handleGuildEmojisUpdate,
|
||||
});
|
||||
});
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
update(guild) {
|
||||
handleCreateOrUpdateGuild.call(this, guild, {});
|
||||
}
|
||||
updateRole(guildId, role) {
|
||||
const guild = this.get(guildId);
|
||||
if (!guild || !guild.roles) return;
|
||||
guild.roles.set(role.id, new Role(role));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildCollection;
|
239
node_modules/discordie/lib/collections/GuildMemberCollection.js
generated
vendored
Normal file
239
node_modules/discordie/lib/collections/GuildMemberCollection.js
generated
vendored
Normal file
@ -0,0 +1,239 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const StatusTypes = Constants.StatusTypes;
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseCollection = require("./BaseCollection");
|
||||
|
||||
const GuildMember = require("../models/GuildMember");
|
||||
|
||||
function createGuildMember(member) {
|
||||
if (member.user) member.id = member.user.id;
|
||||
|
||||
return new GuildMember({
|
||||
id: member.id,
|
||||
guild_id: member.guild_id,
|
||||
nick: member.nick || null,
|
||||
roles: member.roles || [],
|
||||
mute: member.mute || false,
|
||||
deaf: member.deaf || false,
|
||||
self_mute: member.self_mute || false,
|
||||
self_deaf: member.self_deaf || false,
|
||||
joined_at: member.joined_at
|
||||
});
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data) {
|
||||
this.clear();
|
||||
data.guilds.forEach(guild => handleCreateGuild.call(this, guild));
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildMemberCreateOrUpdate(member, e) {
|
||||
const memberCollection = this.get(member.guild_id);
|
||||
if (!memberCollection) return true;
|
||||
|
||||
const prev = memberCollection.get(member.user.id);
|
||||
const next = createGuildMember(member);
|
||||
memberCollection.mergeOrSet(member.user.id, next);
|
||||
|
||||
if (e.type === Events.GUILD_MEMBER_UPDATE) {
|
||||
e.data._prev = prev;
|
||||
e.data._next = next;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildMemberRemove(member, e) {
|
||||
const memberCollection = this.get(member.guild_id);
|
||||
if (!memberCollection) return true;
|
||||
|
||||
const oldMember = memberCollection.get(member.user.id);
|
||||
if (oldMember) e.data._cached = oldMember;
|
||||
|
||||
memberCollection.delete(member.user.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleCreateGuild(guild) {
|
||||
if (!guild || guild.unavailable) return true;
|
||||
|
||||
if (!this._discordie._guilds.get(guild.id)) return true; // GUILD_SYNC case
|
||||
|
||||
const memberCollection = new BaseCollection();
|
||||
this.set(guild.id, memberCollection);
|
||||
|
||||
guild.members.forEach(member => {
|
||||
member.guild_id = guild.id;
|
||||
memberCollection.set(member.user.id, createGuildMember(member));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleDeleteGuild(guild) {
|
||||
this.delete(guild.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleVoiceStateUpdate(data) {
|
||||
const memberCollection = this.get(data.guild_id);
|
||||
if (!memberCollection) return true;
|
||||
const member = memberCollection.get(data.user_id);
|
||||
if (!member) return true;
|
||||
memberCollection.set(data.user_id,
|
||||
member.merge({
|
||||
mute: data.mute,
|
||||
deaf: data.deaf,
|
||||
self_mute: data.self_mute,
|
||||
self_deaf: data.self_deaf
|
||||
})
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handlePresenceUpdate(presence) {
|
||||
if (!presence.user || !presence.user.id) return true;
|
||||
|
||||
// add members only for online users and if presence is not partial
|
||||
if (presence.status == StatusTypes.OFFLINE || !presence.user.username)
|
||||
return true;
|
||||
|
||||
const memberCollection = this.get(presence.guild_id);
|
||||
if (!memberCollection) return true;
|
||||
|
||||
const cachedMember = memberCollection.get(presence.user.id);
|
||||
if (!cachedMember) {
|
||||
// note: presences only contain roles
|
||||
memberCollection.set(presence.user.id, createGuildMember(presence));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildMembersChunk(chunk) {
|
||||
var guildId = chunk.guild_id;
|
||||
if (!guildId || !chunk.members) return true;
|
||||
|
||||
var state = this._guildMemberChunks[guildId];
|
||||
if (!state) return true;
|
||||
|
||||
var guild = this._discordie._guilds.get(guildId);
|
||||
if (!guild) return true;
|
||||
|
||||
const memberCollection = this.get(guildId);
|
||||
if (!memberCollection) return true;
|
||||
|
||||
chunk.members.forEach(member => {
|
||||
member.guild_id = guildId;
|
||||
memberCollection.mergeOrSet(member.user.id, createGuildMember(member))
|
||||
});
|
||||
if (memberCollection.size >= guild.member_count) state.resolve();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
class GuildMemberCollection extends BaseCollection {
|
||||
constructor(discordie, gateway) {
|
||||
super();
|
||||
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
GUILD_SYNC: handleCreateGuild,
|
||||
GUILD_CREATE: handleCreateGuild,
|
||||
GUILD_DELETE: handleDeleteGuild,
|
||||
GUILD_MEMBER_ADD: handleGuildMemberCreateOrUpdate,
|
||||
GUILD_MEMBER_UPDATE: handleGuildMemberCreateOrUpdate,
|
||||
GUILD_MEMBER_REMOVE: handleGuildMemberRemove,
|
||||
VOICE_STATE_UPDATE: handleVoiceStateUpdate,
|
||||
PRESENCE_UPDATE: handlePresenceUpdate,
|
||||
GUILD_MEMBERS_CHUNK: handleGuildMembersChunk
|
||||
});
|
||||
});
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISCONNECT, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
for (var guildId in this._guildMemberChunks) {
|
||||
var state = this._guildMemberChunks[guildId];
|
||||
if (!state) continue;
|
||||
state.reject(new Error("Gateway disconnect"));
|
||||
}
|
||||
this._guildMemberChunks = {};
|
||||
});
|
||||
|
||||
this._guildMemberChunks = {};
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
fetchMembers(guilds){
|
||||
const gateway = this._discordie.gatewaySocket;
|
||||
if (!gateway || !gateway.connected)
|
||||
return Promise.reject(new Error("No gateway socket (not connected)"));
|
||||
|
||||
const largeGuilds =
|
||||
Array.from(this._discordie._guilds.values())
|
||||
.filter(guild => {
|
||||
if (!guild.large) return false;
|
||||
var cachedMembers = this._discordie._members.get(guild.id);
|
||||
if (!cachedMembers) return false;
|
||||
return guild.member_count > cachedMembers.size;
|
||||
})
|
||||
.map(guild => guild.id);
|
||||
|
||||
// filter out only requested guilds (if specified) from large ones
|
||||
// return a resolved promise if no large guilds in the list
|
||||
let targetGuilds =
|
||||
!guilds ?
|
||||
largeGuilds :
|
||||
largeGuilds.filter(guild => guilds.indexOf(guild) >= 0);
|
||||
|
||||
if (!targetGuilds.length) return Promise.resolve();
|
||||
|
||||
targetGuilds.forEach(guildId => {
|
||||
if (this._guildMemberChunks[guildId]) return;
|
||||
|
||||
var state = {promise: null, resolve: null, reject: null, timer: null};
|
||||
state.promise = new Promise((rs, rj) => {
|
||||
const destroyState = () => {
|
||||
if (!state.timer) return;
|
||||
clearTimeout(state.timer);
|
||||
state.timer = null;
|
||||
delete this._guildMemberChunks[guildId];
|
||||
};
|
||||
state.resolve = result => { destroyState(); return rs(result); };
|
||||
state.reject = reason => { destroyState(); return rj(reason); };
|
||||
});
|
||||
state.timer = setTimeout(() => {
|
||||
if (!this._guildMemberChunks[guildId]) return;
|
||||
state.reject(new Error(
|
||||
"Guild member request timed out (" + guildId + ")"
|
||||
));
|
||||
delete this._guildMemberChunks[guildId];
|
||||
}, 60000);
|
||||
this._guildMemberChunks[guildId] = state;
|
||||
});
|
||||
|
||||
gateway.requestGuildMembers(targetGuilds);
|
||||
|
||||
var targetPromises =
|
||||
targetGuilds.map(guildId => this._guildMemberChunks[guildId].promise);
|
||||
|
||||
return Promise.all(targetPromises);
|
||||
}
|
||||
getMember(guildId, userId) {
|
||||
const memberCollection = this.get(guildId);
|
||||
if (!memberCollection) return null;
|
||||
return memberCollection.get(userId);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildMemberCollection;
|
174
node_modules/discordie/lib/collections/GuildSyncCollection.js
generated
vendored
Normal file
174
node_modules/discordie/lib/collections/GuildSyncCollection.js
generated
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
const GUILD_SYNC_TIMEOUT = 3000;
|
||||
|
||||
function emitTaskFinished(gw) {
|
||||
this._syncingGuilds.clear();
|
||||
|
||||
this._discordie.Dispatcher.emit(Events.READY_TASK_FINISHED, {
|
||||
socket: gw,
|
||||
name: this.constructor.name,
|
||||
handler: this
|
||||
});
|
||||
}
|
||||
|
||||
function scheduleReadyTimeout(gw) {
|
||||
this._syncingGuildsTimeout = setTimeout(() => {
|
||||
this._syncingGuildsTimeout = null;
|
||||
if (!this._discordie.connected) return;
|
||||
|
||||
setImmediate(() => emitTaskFinished.call(this, gw));
|
||||
}, GUILD_SYNC_TIMEOUT);
|
||||
}
|
||||
|
||||
function maybeReady(gw) {
|
||||
if (this._syncingGuildsTimeout) {
|
||||
clearTimeout(this._syncingGuildsTimeout);
|
||||
}
|
||||
if (this._syncingGuilds.size) {
|
||||
scheduleReadyTimeout.call(this, gw);
|
||||
} else {
|
||||
setImmediate(() => emitTaskFinished.call(this, gw));
|
||||
}
|
||||
}
|
||||
|
||||
function handleExecuteReadyTask(data, e) {
|
||||
clearAll.call(this);
|
||||
|
||||
if (this.isSupported(e.socket)) {
|
||||
data.guilds.forEach(guild => {
|
||||
this.add(guild.id);
|
||||
this._syncingGuilds.add(guild.id);
|
||||
});
|
||||
commit.call(this);
|
||||
}
|
||||
|
||||
maybeReady.call(this, e.socket);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildCreate(guild, e) {
|
||||
if (!this.isSupported(e.socket)) return true;
|
||||
|
||||
// ignore if became available
|
||||
if (this._discordie.UnavailableGuilds.isGuildAvailable(guild)) return true;
|
||||
|
||||
this.sync(guild);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildSync(guild, e) {
|
||||
if (this._syncingGuilds.has(guild.id)) {
|
||||
this._syncingGuilds.delete(guild.id);
|
||||
|
||||
maybeReady.call(this, e.socket);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildDelete(guild, e) {
|
||||
if (!this.isSupported(e.socket)) return true;
|
||||
if (guild.unavailable) return true;
|
||||
this.unsync(guild);
|
||||
return true;
|
||||
}
|
||||
|
||||
function commit() {
|
||||
const gateway = this._gateway();
|
||||
if (!gateway || !gateway.connected) return;
|
||||
gateway.syncGuilds(Array.from(this));
|
||||
}
|
||||
|
||||
function clearAll() {
|
||||
this.clear();
|
||||
this._syncingGuilds.clear();
|
||||
}
|
||||
|
||||
class GuildSyncCollection extends Set {
|
||||
constructor(discordie, gateway) {
|
||||
super();
|
||||
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
GUILD_SYNC: handleGuildSync,
|
||||
GUILD_CREATE: handleGuildCreate,
|
||||
GUILD_DELETE: handleGuildDelete,
|
||||
});
|
||||
});
|
||||
|
||||
this._discordie = discordie;
|
||||
this._gateway = gateway;
|
||||
|
||||
this._syncingGuilds = new Set();
|
||||
this._syncingGuildsTimeout = null;
|
||||
|
||||
Utils.privatify(this);
|
||||
}
|
||||
_executeReadyTask(data, socket) {
|
||||
handleExecuteReadyTask.call(this, data, {socket});
|
||||
}
|
||||
isSupported(socket) {
|
||||
if (!socket) socket = this._gateway();
|
||||
if (!socket) return false;
|
||||
return socket.remoteGatewayVersion >= 5 && !this._discordie._user.bot;
|
||||
}
|
||||
sync(guild) {
|
||||
if (!this.isSupported()) return false;
|
||||
if (!guild) return false;
|
||||
|
||||
if (Array.isArray(guild)) {
|
||||
const guilds = guild
|
||||
.map(g => g.id || g.valueOf())
|
||||
.filter(id => !this.has(id));
|
||||
if (!guilds.length) return false;
|
||||
guilds.forEach(id => this.add(id));
|
||||
} else {
|
||||
if (this.has(guild.id)) return false;
|
||||
this.add(guild.id);
|
||||
}
|
||||
|
||||
commit.call(this);
|
||||
return true;
|
||||
}
|
||||
unsync(guild) {
|
||||
if (!this.isSupported()) return false;
|
||||
if (!guild) return false;
|
||||
|
||||
if (Array.isArray(guild)) {
|
||||
const guilds = guild
|
||||
.map(g => g.id || g.valueOf())
|
||||
.filter(id => this.has(id));
|
||||
if (!guilds.length) return false;
|
||||
guilds.forEach(id => this.delete(id));
|
||||
} else {
|
||||
if (!this.delete(guild.id)) return false;
|
||||
}
|
||||
|
||||
commit.call(this);
|
||||
return true;
|
||||
}
|
||||
syncAll() {
|
||||
const available = this._discordie.Guilds.map(g => g.valueOf());
|
||||
const unavailable = this._discordie.UnavailableGuilds;
|
||||
const all = available.concat(unavailable);
|
||||
return this.sync(all);
|
||||
}
|
||||
unsyncAll() {
|
||||
if (!this.isSupported()) return false;
|
||||
if (!this.size) return false;
|
||||
this.clear();
|
||||
commit.call(this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildSyncCollection;
|
393
node_modules/discordie/lib/collections/MessageCollection.js
generated
vendored
Normal file
393
node_modules/discordie/lib/collections/MessageCollection.js
generated
vendored
Normal file
@ -0,0 +1,393 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseCollection = require("./BaseCollection");
|
||||
const LimitedCache = require("../core/LimitedCache");
|
||||
|
||||
const Message = require("../models/Message");
|
||||
|
||||
function getOrCreateChannelCache(channelId) {
|
||||
return (
|
||||
this._messagesByChannel[channelId] =
|
||||
this._messagesByChannel[channelId] ||
|
||||
new LimitedCache(this._messageLimit)
|
||||
);
|
||||
}
|
||||
|
||||
function updatePinnedMessages(channelId, messageId, message) {
|
||||
if (message && message.pinned && !message.deleted) {
|
||||
var channelPinned =
|
||||
this._pinnedMessagesByChannel[channelId] =
|
||||
this._pinnedMessagesByChannel[channelId] || [];
|
||||
|
||||
// insert or replace
|
||||
const idx = channelPinned.findIndex(msg => msg.id === messageId);
|
||||
if (idx < 0) channelPinned.unshift(message);
|
||||
else channelPinned[idx] = message;
|
||||
} else {
|
||||
var channelPinned = this._pinnedMessagesByChannel[channelId];
|
||||
if (channelPinned) {
|
||||
// delete if exists
|
||||
const idx = channelPinned.findIndex(msg => msg.id === messageId);
|
||||
if (idx >= 0) channelPinned.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updateMessages(channelId, messageId, msg) {
|
||||
const messages = getOrCreateChannelCache.call(this, channelId);
|
||||
|
||||
if (msg.nonce && messages.has(msg.nonce)) {
|
||||
messages.rename(msg.nonce, messageId);
|
||||
}
|
||||
|
||||
var edited = true;
|
||||
var message = null;
|
||||
if (messages.has(messageId)) {
|
||||
edited = !!msg.edited_timestamp;
|
||||
messages.set(messageId, message = messages.get(messageId).merge(msg));
|
||||
} else {
|
||||
messages.set(messageId, message = new Message(msg));
|
||||
}
|
||||
|
||||
if (edited) {
|
||||
const edits = this._messageEdits[messageId] || [];
|
||||
this._messageEdits[messageId] = edits;
|
||||
|
||||
var edit = message.merge({embeds: [], reactions: []});
|
||||
edits.push(edit);
|
||||
trimEdits.call(this, messageId);
|
||||
}
|
||||
}
|
||||
|
||||
function trimEdits(messageId) {
|
||||
if (!messageId) {
|
||||
for (var id in this._messageEdits)
|
||||
if (id) trimEdits.call(this, id);
|
||||
}
|
||||
const edits = this._messageEdits[messageId];
|
||||
if (!edits) return;
|
||||
if (edits.length > this._editsLimit)
|
||||
edits.splice(0, edits.length - this._editsLimit);
|
||||
}
|
||||
|
||||
function handleMessageCreate(msg) {
|
||||
msg.deleted = false;
|
||||
updateMessages.call(this, msg.channel_id, msg.id, msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleMessageUpdate(msg) {
|
||||
msg.deleted = false;
|
||||
|
||||
// update pinned cache only if pinned messages have been fetched
|
||||
var channelPinned = this._pinnedMessagesByChannel[msg.channel_id];
|
||||
if (channelPinned) {
|
||||
updatePinnedMessages.call(this, msg.channel_id, msg.id, msg);
|
||||
}
|
||||
|
||||
const channelCache = this._messagesByChannel[msg.channel_id];
|
||||
if (!channelCache || !channelCache.has(msg.id)) return true;
|
||||
|
||||
updateMessages.call(this, msg.channel_id, msg.id, msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleMessageDelete(msg) {
|
||||
msg.deleted = true;
|
||||
|
||||
updatePinnedMessages.call(this, msg.channel_id, msg.id, msg);
|
||||
|
||||
const channelCache = this._messagesByChannel[msg.channel_id];
|
||||
if (!channelCache || !channelCache.has(msg.id)) return true;
|
||||
|
||||
updateMessages.call(this, msg.channel_id, msg.id, msg);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleMessageDeleteBulk(msg) {
|
||||
const channelCache = this._messagesByChannel[msg.channel_id];
|
||||
if (!channelCache) return true;
|
||||
|
||||
const update = { deleted: true };
|
||||
|
||||
msg.ids.forEach(id => {
|
||||
updatePinnedMessages.call(this, msg.channel_id, id, update);
|
||||
|
||||
if (!channelCache.has(id)) return;
|
||||
updateMessages.call(this, msg.channel_id, id, update);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleReaction(reaction, e) {
|
||||
const channelCache = this._messagesByChannel[reaction.channel_id];
|
||||
if (!channelCache) return true;
|
||||
|
||||
const localUser = this._discordie._user || {};
|
||||
const me = (localUser.id == reaction.user_id);
|
||||
|
||||
var message = channelCache.get(reaction.message_id);
|
||||
if (!message) return true;
|
||||
|
||||
const emoji = reaction.emoji;
|
||||
const idx = message.reactions
|
||||
.findIndex(r => r.emoji.id === emoji.id && r.emoji.name == emoji.name);
|
||||
const old = message.reactions[idx];
|
||||
|
||||
if (e.type === Events.MESSAGE_REACTION_ADD) {
|
||||
if (!message.reactions) {
|
||||
message = message.merge({reactions: []});
|
||||
channelCache.set(reaction.message_id, message);
|
||||
}
|
||||
|
||||
if (old) {
|
||||
old.count += 1;
|
||||
if (me) old.me = true;
|
||||
} else {
|
||||
message.reactions.push({emoji, me, count: 1});
|
||||
}
|
||||
}
|
||||
|
||||
if (e.type === Events.MESSAGE_REACTION_REMOVE) {
|
||||
if (old) {
|
||||
old.count -= 1;
|
||||
if (me) old.me = false;
|
||||
if (old.count <= 0) message.reactions.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleReactionRemoveAll(reaction, e) {
|
||||
const channelCache = this._messagesByChannel[reaction.channel_id];
|
||||
if (!channelCache) return true;
|
||||
|
||||
const message = channelCache.get(reaction.message_id);
|
||||
if (!message) return true;
|
||||
|
||||
if (!message.reactions || !message.reactions.length) return true;
|
||||
|
||||
e.data._cached = message.reactions;
|
||||
channelCache.set(reaction.message_id, message.merge({reactions: []}));
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data) {
|
||||
this.purgeAllCache();
|
||||
}
|
||||
|
||||
function handleCleanup() {
|
||||
for (let channelId in this._messagesByChannel) {
|
||||
if (!this._messagesByChannel.hasOwnProperty(channelId)) continue;
|
||||
if (this._discordie._channels.get(channelId)) continue;
|
||||
|
||||
var messageIds = this._messagesByChannel[channelId]._keys;
|
||||
for (var i = 0, len = messageIds.length; i < len; i++)
|
||||
delete this._messageEdits[messageIds[i]];
|
||||
|
||||
delete this._pinnedMessagesByChannel[channelId];
|
||||
delete this._messagesByChannel[channelId];
|
||||
delete this._hasMoreByChannel[channelId];
|
||||
}
|
||||
}
|
||||
|
||||
function handleLoadedMoreMessages(e) {
|
||||
var messagesLength = e.messages.length;
|
||||
if (!messagesLength) return;
|
||||
|
||||
const channelId = e.messages[0].channel_id;
|
||||
if (!e.before && !e.after) {
|
||||
this._hasMoreByChannel[channelId] = (e.limit == messagesLength);
|
||||
}
|
||||
|
||||
const messages = getOrCreateChannelCache.call(this, channelId);
|
||||
|
||||
const limit = messages.limit;
|
||||
messages.setLimit(limit + messagesLength);
|
||||
|
||||
var i = messagesLength;
|
||||
while (i--) {
|
||||
var msg = e.messages[i];
|
||||
updateMessages.call(this, msg.channel_id, msg.id, msg);
|
||||
}
|
||||
|
||||
messages.setLimit(Math.max(messages.size + 500, limit));
|
||||
// increase channel cache limits
|
||||
// in case new messages arrive and invalidate old message references
|
||||
}
|
||||
|
||||
function handleLoadedPinnedMessages(e) {
|
||||
const channelId = e.channelId;
|
||||
const channelPinned =
|
||||
this._pinnedMessagesByChannel[channelId] =
|
||||
this._pinnedMessagesByChannel[channelId] || [];
|
||||
|
||||
var messagesLength = e.messages.length;
|
||||
if (!messagesLength) return;
|
||||
|
||||
const channelCache = this._messagesByChannel[channelId];
|
||||
e.messages.forEach(msg => {
|
||||
const cached = channelCache ? channelCache.get(msg.id) : null;
|
||||
channelPinned.push(cached || new Message(msg));
|
||||
});
|
||||
}
|
||||
|
||||
class MessageCollection {
|
||||
constructor(discordie, gateway) {
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
MESSAGE_CREATE: handleMessageCreate,
|
||||
MESSAGE_UPDATE: handleMessageUpdate,
|
||||
MESSAGE_DELETE: handleMessageDelete,
|
||||
MESSAGE_DELETE_BULK: handleMessageDeleteBulk,
|
||||
CHANNEL_DELETE: handleCleanup,
|
||||
GUILD_DELETE: handleCleanup,
|
||||
MESSAGE_REACTION_ADD: handleReaction,
|
||||
MESSAGE_REACTION_REMOVE: handleReaction,
|
||||
MESSAGE_REACTION_REMOVE_ALL: handleReactionRemoveAll
|
||||
});
|
||||
});
|
||||
|
||||
discordie.Dispatcher.on(Events.LOADED_MORE_MESSAGES,
|
||||
handleLoadedMoreMessages.bind(this));
|
||||
|
||||
discordie.Dispatcher.on(Events.LOADED_PINNED_MESSAGES,
|
||||
handleLoadedPinnedMessages.bind(this));
|
||||
|
||||
this.purgeAllCache();
|
||||
this._messageLimit = 1000;
|
||||
this._editsLimit = 50;
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
|
||||
getChannelMessageLimit(channelId) {
|
||||
if (!this._discordie._channels.get(channelId)) return -1;
|
||||
if (!this._messagesByChannel.hasOwnProperty(channelId)) return -1;
|
||||
return this._messagesByChannel[channelId].limit;
|
||||
}
|
||||
setChannelMessageLimit(channelId, limit) {
|
||||
if (!limit) return false;
|
||||
if (!this._discordie._channels.get(channelId)) return false;
|
||||
const messages = getOrCreateChannelCache.call(this, channelId);
|
||||
messages.setLimit(limit);
|
||||
return true;
|
||||
}
|
||||
|
||||
getMessageLimit() { return this._messageLimit; }
|
||||
setMessageLimit(limit) {
|
||||
if (!limit) return;
|
||||
if (!(limit > 0)) limit = 1;
|
||||
var keys = Object.keys(this._messagesByChannel);
|
||||
for (var i = 0, len = keys.length; i < len; i++) {
|
||||
var cache = this._messagesByChannel[keys[i]];
|
||||
// decrease only for channels with default limit
|
||||
if (!cache) continue;
|
||||
if (cache.limit != this._messageLimit && limit < cache.limit)
|
||||
continue;
|
||||
var removed = cache.setLimit(limit);
|
||||
if (!removed) continue;
|
||||
for (var messageId of removed)
|
||||
delete this._messageEdits[messageId];
|
||||
}
|
||||
this._messageLimit = limit;
|
||||
}
|
||||
|
||||
getEditsLimit() { return this._editsLimit; }
|
||||
setEditsLimit(limit) {
|
||||
if (!limit) return;
|
||||
if (!(limit > 0)) limit = 1;
|
||||
this._editsLimit = limit;
|
||||
trimEdits.call(this);
|
||||
}
|
||||
|
||||
*getIterator() {
|
||||
for (var channelId in this._messagesByChannel) {
|
||||
if (!this._messagesByChannel.hasOwnProperty(channelId)) continue;
|
||||
if (!this._discordie._channels.get(channelId)) continue;
|
||||
var channelMessages = this._messagesByChannel[channelId];
|
||||
var keys = channelMessages._keys;
|
||||
for (var i = 0, len = keys.length; i < len; i++) {
|
||||
var message = channelMessages.get(keys[i]);
|
||||
if (message) yield message;
|
||||
}
|
||||
}
|
||||
}
|
||||
get(messageId) {
|
||||
for (var channelId in this._messagesByChannel) {
|
||||
if (!this._messagesByChannel.hasOwnProperty(channelId)) continue;
|
||||
if (!this._discordie._channels.get(channelId)) continue;
|
||||
var channelMessages = this._messagesByChannel[channelId];
|
||||
var message = channelMessages.get(messageId);
|
||||
if (message) return message;
|
||||
}
|
||||
for (var channelId in this._pinnedMessagesByChannel) {
|
||||
if (!this._pinnedMessagesByChannel.hasOwnProperty(channelId)) continue;
|
||||
if (!this._discordie._channels.get(channelId)) continue;
|
||||
var channelPinned = this._pinnedMessagesByChannel[channelId];
|
||||
var message = channelPinned.find(msg => msg.id === messageId);
|
||||
if (message) return message;
|
||||
}
|
||||
}
|
||||
|
||||
getChannelCache(channelId) {
|
||||
if (!this._discordie._channels.get(channelId)) return null;
|
||||
if (!this._messagesByChannel.hasOwnProperty(channelId)) return null;
|
||||
return this._messagesByChannel[channelId];
|
||||
}
|
||||
purgeChannelCache(channelId) {
|
||||
delete this._hasMoreByChannel[channelId];
|
||||
delete this._messagesByChannel[channelId];
|
||||
}
|
||||
|
||||
getChannelPinned(channelId) {
|
||||
if (!this._discordie._channels.get(channelId)) return null;
|
||||
if (!this._pinnedMessagesByChannel.hasOwnProperty(channelId)) return null;
|
||||
return this._pinnedMessagesByChannel[channelId];
|
||||
}
|
||||
purgeChannelPinned(channelId) {
|
||||
delete this._pinnedMessagesByChannel[channelId];
|
||||
}
|
||||
purgePinned() {
|
||||
this._pinnedMessagesByChannel = {};
|
||||
}
|
||||
|
||||
getEdits(messageId) {
|
||||
var edits = this._messageEdits[messageId];
|
||||
return edits ? edits.slice().reverse() : [];
|
||||
}
|
||||
purgeEdits() {
|
||||
this._messageEdits = {};
|
||||
}
|
||||
|
||||
purgeAllCache() {
|
||||
this._messagesByChannel = {};
|
||||
this._hasMoreByChannel = {};
|
||||
this.purgeEdits();
|
||||
this.purgePinned();
|
||||
}
|
||||
|
||||
create(message) {
|
||||
handleMessageCreate.call(this, message);
|
||||
}
|
||||
update(message) {
|
||||
handleMessageUpdate.call(this, message);
|
||||
}
|
||||
channelHasMore(channelId) {
|
||||
if (this._hasMoreByChannel[channelId] === undefined)
|
||||
return true;
|
||||
return this._hasMoreByChannel[channelId];
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageCollection;
|
162
node_modules/discordie/lib/collections/PresenceCollection.js
generated
vendored
Normal file
162
node_modules/discordie/lib/collections/PresenceCollection.js
generated
vendored
Normal file
@ -0,0 +1,162 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const StatusTypes = Constants.StatusTypes;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseCollection = require("./BaseCollection");
|
||||
|
||||
const User = require("../models/User");
|
||||
|
||||
function updatePresence(guildId, userId, status, game) {
|
||||
if (userId === this._discordie._user.id) return;
|
||||
|
||||
// ignore friend list presences (without `guild_id`)
|
||||
if (!guildId) return;
|
||||
|
||||
// get presences in all guilds
|
||||
var presencesForUser =
|
||||
(this._presencesForGuilds[userId] =
|
||||
this._presencesForGuilds[userId] || {});
|
||||
|
||||
var previousPresencesForUser =
|
||||
(this._previousPresencesForGuilds[userId] =
|
||||
this._previousPresencesForGuilds[userId] || {});
|
||||
|
||||
var previousPresence = presencesForUser[guildId];
|
||||
|
||||
// copy current to previous
|
||||
previousPresencesForUser[guildId] =
|
||||
Object.assign(previousPresencesForUser[guildId] || {}, previousPresence);
|
||||
|
||||
if (!previousPresence)
|
||||
delete previousPresencesForUser[guildId];
|
||||
|
||||
if (status === StatusTypes.OFFLINE) {
|
||||
// delete current presence cache if user is not online anymore
|
||||
delete presencesForUser[guildId];
|
||||
if (!Object.keys(presencesForUser).length) {
|
||||
delete this._presencesForGuilds[userId];
|
||||
}
|
||||
delete this._statuses[userId];
|
||||
delete this._games[userId];
|
||||
} else {
|
||||
// set current presence
|
||||
presencesForUser[guildId] = {status, game};
|
||||
|
||||
// update global status and game (for user statuses in DM list)
|
||||
this._statuses[userId] = status;
|
||||
this._games[userId] = game || null;
|
||||
}
|
||||
}
|
||||
|
||||
function initializeCache() {
|
||||
this._presencesForGuilds = {};
|
||||
this._previousPresencesForGuilds = {};
|
||||
this._statuses = {};
|
||||
this._games = {};
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data) {
|
||||
initializeCache.call(this);
|
||||
data.guilds.forEach(guild => handleGuildCreate.call(this, guild));
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildCreate(guild) {
|
||||
if (!guild || guild.unavailable) return true;
|
||||
guild.presences.forEach(presence => {
|
||||
updatePresence.call(this,
|
||||
guild.id,
|
||||
presence.user.id,
|
||||
presence.status,
|
||||
presence.game
|
||||
);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildDelete(guild) {
|
||||
for (let userId of Object.keys(this._presencesForGuilds)) {
|
||||
if (!this._presencesForGuilds[userId][guild.id]) continue;
|
||||
updatePresence.call(this, guild.id, userId, StatusTypes.OFFLINE, null);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handlePresenceUpdate(presence) {
|
||||
updatePresence.call(this,
|
||||
presence.guild_id,
|
||||
presence.user.id,
|
||||
presence.status,
|
||||
presence.game
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
function getPresence(collection, userId, guildId) {
|
||||
if (collection.hasOwnProperty(userId)) {
|
||||
const presencesForUser = collection[userId];
|
||||
guildId = guildId || Object.keys(presencesForUser)[0];
|
||||
if (presencesForUser.hasOwnProperty(guildId)) {
|
||||
return presencesForUser[guildId];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
class PresenceCollection {
|
||||
constructor(discordie, gateway) {
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
GUILD_SYNC: handleGuildCreate,
|
||||
GUILD_CREATE: handleGuildCreate,
|
||||
GUILD_DELETE: handleGuildDelete,
|
||||
PRESENCE_UPDATE: handlePresenceUpdate
|
||||
});
|
||||
});
|
||||
|
||||
initializeCache.call(this);
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
getStatus(userId, guildId) {
|
||||
if (this._discordie._user && this._discordie._user.id == userId) {
|
||||
return this._discordie._user.status;
|
||||
}
|
||||
const presence = getPresence.call(this,
|
||||
this._presencesForGuilds, userId, guildId
|
||||
) || {};
|
||||
return presence.status || StatusTypes.OFFLINE;
|
||||
}
|
||||
getPreviousStatus(userId, guildId) {
|
||||
const presence = getPresence.call(this,
|
||||
this._previousPresencesForGuilds, userId, guildId
|
||||
) || {};
|
||||
return presence.status || StatusTypes.OFFLINE;
|
||||
}
|
||||
getGame(userId, guildId) {
|
||||
if (this._discordie._user && this._discordie._user.id == userId) {
|
||||
return this._discordie._user.game;
|
||||
}
|
||||
const presence = getPresence.call(this,
|
||||
this._presencesForGuilds, userId, guildId
|
||||
) || {};
|
||||
return presence.game || null;
|
||||
}
|
||||
getPreviousGame(userId, guildId) {
|
||||
const presence = getPresence.call(this,
|
||||
this._previousPresencesForGuilds, userId, guildId
|
||||
) || {};
|
||||
return presence.game || null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PresenceCollection;
|
135
node_modules/discordie/lib/collections/UnavailableGuildCollection.js
generated
vendored
Normal file
135
node_modules/discordie/lib/collections/UnavailableGuildCollection.js
generated
vendored
Normal file
@ -0,0 +1,135 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseArrayCollection = require("./BaseArrayCollection");
|
||||
|
||||
const GUILD_STREAMING_TIMEOUT = 3000;
|
||||
|
||||
function emitReady(gw) {
|
||||
const timedOut = Array.from(this._streamingGuilds);
|
||||
this._streamingGuilds.clear();
|
||||
|
||||
this._discordie.Dispatcher.emit(Events.COLLECTION_READY, {
|
||||
socket: gw,
|
||||
name: this.constructor.name,
|
||||
collection: this
|
||||
});
|
||||
|
||||
if (!timedOut.length) return;
|
||||
timedOut.forEach(id => {
|
||||
this._discordie.Dispatcher.emit(Events.GUILD_UNAVAILABLE, {
|
||||
socket: gw,
|
||||
guildId: id
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function scheduleReadyTimeout(gw) {
|
||||
this._streamingGuildsTimeout = setTimeout(() => {
|
||||
this._streamingGuildsTimeout = null;
|
||||
if (!this._discordie.connected) return;
|
||||
|
||||
setImmediate(() => emitReady.call(this, gw));
|
||||
}, GUILD_STREAMING_TIMEOUT);
|
||||
}
|
||||
|
||||
function maybeReady(gw) {
|
||||
if (this._streamingGuildsTimeout) {
|
||||
clearTimeout(this._streamingGuildsTimeout);
|
||||
}
|
||||
if (this._streamingGuilds.size) {
|
||||
scheduleReadyTimeout.call(this, gw);
|
||||
} else {
|
||||
setImmediate(() => emitReady.call(this, gw));
|
||||
}
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data, e) {
|
||||
clearCollections.call(this);
|
||||
|
||||
data.guilds.forEach(guild => {
|
||||
if (!guild.unavailable) return;
|
||||
addUnavailable.call(this, guild.id);
|
||||
this._streamingGuilds.add(guild.id);
|
||||
});
|
||||
|
||||
maybeReady.call(this, e.socket);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildCreate(guild, e) {
|
||||
handleUnavailable.call(this, guild);
|
||||
|
||||
if (this.isGuildAvailable(guild) && this._streamingGuilds.has(guild.id)) {
|
||||
e.suppress = true;
|
||||
this._streamingGuilds.delete(guild.id);
|
||||
|
||||
maybeReady.call(this, e.socket);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildDelete(guild) {
|
||||
handleUnavailable.call(this, guild);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleUnavailable(guild) {
|
||||
if (guild.unavailable) {
|
||||
addUnavailable.call(this, guild.id)
|
||||
} else {
|
||||
removeUnavailable.call(this, guild.id);
|
||||
}
|
||||
}
|
||||
|
||||
function addUnavailable(id) {
|
||||
if (this._set.has(id)) return;
|
||||
this._set.add(id);
|
||||
|
||||
this.push(id);
|
||||
}
|
||||
function removeUnavailable(id) {
|
||||
if (!this._set.has(id)) return;
|
||||
this._set.delete(id);
|
||||
|
||||
var idx = this.indexOf(id);
|
||||
this.splice(idx, 1);
|
||||
}
|
||||
function clearCollections() {
|
||||
this._streamingGuilds.clear();
|
||||
this._set.clear();
|
||||
this.length = 0;
|
||||
}
|
||||
|
||||
class UnavailableGuildCollection extends BaseArrayCollection {
|
||||
static _constructor(discordie, gateway) {
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
GUILD_CREATE: handleGuildCreate,
|
||||
GUILD_DELETE: handleGuildDelete,
|
||||
});
|
||||
});
|
||||
|
||||
this._discordie = discordie;
|
||||
this._set = new Set();
|
||||
|
||||
this._streamingGuilds = new Set();
|
||||
this._streamingGuildsTimeout = null;
|
||||
|
||||
Utils.privatify(this);
|
||||
}
|
||||
isGuildAvailable(guild) {
|
||||
// unavailable guilds that became available have key `unavailable`
|
||||
return guild.unavailable === false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UnavailableGuildCollection;
|
191
node_modules/discordie/lib/collections/UserCollection.js
generated
vendored
Normal file
191
node_modules/discordie/lib/collections/UserCollection.js
generated
vendored
Normal file
@ -0,0 +1,191 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseCollection = require("./BaseCollection");
|
||||
|
||||
const User = require("../models/User");
|
||||
const AuthenticatedUser = require("../models/AuthenticatedUser");
|
||||
|
||||
function handleConnectionOpen(data) {
|
||||
this.clear();
|
||||
this.set(data.user.id, new AuthenticatedUser(data.user));
|
||||
|
||||
data.guilds.forEach(guild => {
|
||||
if (guild.unavailable) return;
|
||||
guild.members.forEach(member => {
|
||||
if (member.user.id == data.user.id) return;
|
||||
this.set(member.user.id, new User(member.user));
|
||||
});
|
||||
});
|
||||
|
||||
data.private_channels.forEach(channel => {
|
||||
if (!channel.recipients) return;
|
||||
channel.recipients.forEach(u => {
|
||||
if (u.id === data.user.id) return;
|
||||
this.set(u.id, new User(u));
|
||||
});
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleUpdateUser(user) {
|
||||
const cachedUser = this._discordie._user;
|
||||
delete user.token;
|
||||
this._discordie._user = new AuthenticatedUser(
|
||||
cachedUser ? cachedUser.merge(user) : user
|
||||
);
|
||||
this.mergeOrSet(user.id, this._discordie._user);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleLoadedMoreOrPinnedMessages(e) {
|
||||
e.messages.forEach(message => {
|
||||
this.mergeOrSet(message.author.id, new User(message.author));
|
||||
message.mentions.forEach(mention => {
|
||||
this.mergeOrSet(mention.id, new User(mention));
|
||||
});
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleIncomingMessage(message) {
|
||||
if (message.author) {
|
||||
this.mergeOrSet(message.author.id, new User(message.author));
|
||||
}
|
||||
if (message.mentions) {
|
||||
message.mentions.forEach(mention => {
|
||||
this.mergeOrSet(mention.id, new User(mention));
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleCreateOrUpdateChannel(channel) {
|
||||
if (channel.recipient) {
|
||||
this.mergeOrSet(channel.recipient.id, new User(channel.recipient));
|
||||
}
|
||||
if (channel.recipients) {
|
||||
channel.recipients.forEach(u => this.mergeOrSet(u.id, new User(u)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function handlePresenceUpdate(presence, e) {
|
||||
if (!presence.user || !presence.user.id) return true;
|
||||
|
||||
const cachedUser = this.get(presence.user.id);
|
||||
if (!cachedUser) {
|
||||
// update 2015-10-22:
|
||||
// Discord client now creates local GUILD_MEMBER_ADD event
|
||||
// update 2015-12-01:
|
||||
// Discord client creates local GUILD_MEMBER_ADD event only for
|
||||
// online users with `user.username != null`
|
||||
this.set(presence.user.id, new User(presence.user));
|
||||
return true;
|
||||
}
|
||||
|
||||
const replacer = (hasChanges, key) => {
|
||||
if (presence.user.hasOwnProperty(key)) {
|
||||
hasChanges = hasChanges ||
|
||||
(cachedUser[key] != presence.user[key]);
|
||||
}
|
||||
return hasChanges;
|
||||
};
|
||||
const hasChanges =
|
||||
["username", "avatar", "discriminator"].reduce(replacer, false);
|
||||
|
||||
if (hasChanges) {
|
||||
const oldUser = this.get(cachedUser.id);
|
||||
this.mergeOrSet(cachedUser.id, new User(presence.user));
|
||||
const newUser = this.get(cachedUser.id);
|
||||
|
||||
this._discordie.Dispatcher.emit(Events.PRESENCE_MEMBER_INFO_UPDATE, {
|
||||
socket: e.socket,
|
||||
old: oldUser,
|
||||
new: newUser
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleLoadedGuildBans(bans) {
|
||||
bans.forEach(ban => {
|
||||
this.mergeOrSet(ban.user.id, new User(ban.user));
|
||||
});
|
||||
}
|
||||
|
||||
function handleBanOrMember(member) {
|
||||
this.mergeOrSet(member.user.id, new User(member.user));
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildCreate(guild) {
|
||||
if (!guild || guild.unavailable) return true;
|
||||
guild.members.forEach(member => {
|
||||
if (this._discordie._user.id == member.user.id) return;
|
||||
this.mergeOrSet(member.user.id, new User(member.user));
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildMembersChunk(chunk) {
|
||||
if (!chunk.members) return true;
|
||||
handleGuildCreate.call(this, chunk);
|
||||
return true;
|
||||
}
|
||||
|
||||
class UserCollection extends BaseCollection {
|
||||
constructor(discordie, gateway) {
|
||||
super();
|
||||
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
USER_UPDATE: handleUpdateUser,
|
||||
PRESENCE_UPDATE: handlePresenceUpdate,
|
||||
MESSAGE_CREATE: handleIncomingMessage,
|
||||
MESSAGE_UPDATE: handleIncomingMessage,
|
||||
GUILD_SYNC: handleGuildCreate,
|
||||
GUILD_CREATE: handleGuildCreate,
|
||||
GUILD_BAN_ADD: handleBanOrMember,
|
||||
GUILD_BAN_REMOVE: handleBanOrMember,
|
||||
GUILD_MEMBER_ADD: handleBanOrMember,
|
||||
GUILD_MEMBER_REMOVE: handleBanOrMember,
|
||||
CHANNEL_RECIPIENT_ADD: handleBanOrMember,
|
||||
CHANNEL_RECIPIENT_REMOVE: handleBanOrMember,
|
||||
CHANNEL_CREATE: handleCreateOrUpdateChannel,
|
||||
CHANNEL_UPDATE: handleCreateOrUpdateChannel,
|
||||
GUILD_MEMBERS_CHUNK: handleGuildMembersChunk
|
||||
});
|
||||
});
|
||||
|
||||
discordie.Dispatcher.on(Events.LOADED_MORE_MESSAGES,
|
||||
handleLoadedMoreOrPinnedMessages.bind(this));
|
||||
|
||||
discordie.Dispatcher.on(Events.LOADED_PINNED_MESSAGES,
|
||||
handleLoadedMoreOrPinnedMessages.bind(this));
|
||||
|
||||
discordie.Dispatcher.on(Events.LOADED_GUILD_BANS,
|
||||
handleLoadedGuildBans.bind(this));
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
updateAuthenticatedUser(user) {
|
||||
handleUpdateUser.call(this, user);
|
||||
}
|
||||
update(user) {
|
||||
this.mergeOrSet(user.id, new User(user));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = UserCollection;
|
273
node_modules/discordie/lib/collections/VoiceConnectionCollection.js
generated
vendored
Normal file
273
node_modules/discordie/lib/collections/VoiceConnectionCollection.js
generated
vendored
Normal file
@ -0,0 +1,273 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Errors = Constants.Errors;
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseArrayCollection = require("./BaseArrayCollection");
|
||||
const IVoiceConnection = require("../interfaces/IVoiceConnection");
|
||||
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
class VoiceConnectionInfo {
|
||||
constructor(gatewaySocket, voiceSocket, voiceConnection) {
|
||||
/**
|
||||
* @instance
|
||||
* @memberOf VoiceConnectionInfo
|
||||
* @name gatewaySocket
|
||||
* @returns {GatewaySocket}
|
||||
*/
|
||||
this.gatewaySocket = gatewaySocket;
|
||||
|
||||
/**
|
||||
* @instance
|
||||
* @memberOf VoiceConnectionInfo
|
||||
* @name voiceSocket
|
||||
* @returns {VoiceSocket}
|
||||
*/
|
||||
this.voiceSocket = voiceSocket;
|
||||
|
||||
/**
|
||||
* @instance
|
||||
* @memberOf VoiceConnectionInfo
|
||||
* @name voiceConnection
|
||||
* @returns {IVoiceConnection}
|
||||
*/
|
||||
this.voiceConnection = voiceConnection;
|
||||
Object.freeze(this);
|
||||
}
|
||||
}
|
||||
|
||||
class VoiceConnectionCollection extends BaseArrayCollection {
|
||||
static _constructor(discordie, primaryGateway) {
|
||||
this._gateways = new Set();
|
||||
|
||||
this._pendingConnections = new Map();
|
||||
// handle pending disconnects first to avoid firing a rejected pending
|
||||
discordie.Dispatcher.on(Events.VOICESOCKET_DISCONNECT, e => {
|
||||
var voiceSocket = e.socket;
|
||||
var gatewaySocket = e.socket.gatewaySocket;
|
||||
|
||||
var guildId = voiceSocket.guildId;
|
||||
|
||||
const awaitingEndpoint =
|
||||
e.error && e.error.message == Errors.VOICE_CHANGING_SERVER;
|
||||
|
||||
if (awaitingEndpoint) {
|
||||
this._createPending(guildId);
|
||||
} else {
|
||||
var pending = this._pendingConnections.get(guildId);
|
||||
if (!pending) return;
|
||||
|
||||
gatewaySocket.disconnectVoice(guildId);
|
||||
|
||||
this._pendingConnections.delete(guildId);
|
||||
e ? pending.reject(e.error) : pending.reject();
|
||||
}
|
||||
});
|
||||
|
||||
// process voice connections
|
||||
discordie.Dispatcher.on(Events.VOICE_SESSION_DESCRIPTION, e => {
|
||||
const gw = e.socket.gatewaySocket;
|
||||
const voicews = e.socket;
|
||||
|
||||
const voiceConnection = new IVoiceConnection(discordie, gw, voicews);
|
||||
this.push(new VoiceConnectionInfo(gw, voicews, voiceConnection));
|
||||
|
||||
discordie.Dispatcher.emit(Events.VOICE_CONNECTED, {
|
||||
socket: voicews,
|
||||
voiceConnection: voiceConnection
|
||||
});
|
||||
});
|
||||
discordie.Dispatcher.on(Events.VOICESOCKET_DISCONNECT, e => {
|
||||
const idx = this.findIndex(c => c.voiceSocket == e.socket);
|
||||
if (idx < 0) return;
|
||||
|
||||
var info = this[idx];
|
||||
|
||||
// delete from this array
|
||||
this.splice(idx, 1);
|
||||
|
||||
var guildId = info.voiceSocket.guildId;
|
||||
|
||||
const awaitingEndpoint =
|
||||
e.error && e.error.message == Errors.VOICE_CHANGING_SERVER;
|
||||
|
||||
const manual =
|
||||
e.error && e.error.message == Errors.VOICE_MANUAL_DISCONNECT;
|
||||
|
||||
const endpointAwait =
|
||||
awaitingEndpoint ? this._createPending(guildId) : null;
|
||||
|
||||
discordie.Dispatcher.emit(Events.VOICE_DISCONNECTED, {
|
||||
socket: info.voiceSocket,
|
||||
voiceConnection: info.voiceConnection,
|
||||
error: (e.error instanceof Error) ? e.error : null,
|
||||
manual, endpointAwait
|
||||
});
|
||||
|
||||
if (guildId && !endpointAwait)
|
||||
info.gatewaySocket.disconnectVoice(guildId);
|
||||
info.voiceConnection.dispose();
|
||||
});
|
||||
|
||||
// resolve promise when we have a voice connection created
|
||||
discordie.Dispatcher.on(Events.VOICE_SESSION_DESCRIPTION, e => {
|
||||
var voiceSocket = e.socket;
|
||||
|
||||
var guildId = voiceSocket.guildId;
|
||||
var pending = this._pendingConnections.get(guildId);
|
||||
if (!pending) return;
|
||||
|
||||
this._pendingConnections.delete(guildId);
|
||||
pending.resolve(this.getForVoiceSocket(voiceSocket));
|
||||
});
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.type === "READY" || e.type === "RESUMED") {
|
||||
this._gateways.add(e.socket);
|
||||
}
|
||||
|
||||
// process edge cases
|
||||
if (e.type === "CALL_DELETE") {
|
||||
const info = this.getForChannel(e.data.channel_id);
|
||||
if (!info) return;
|
||||
if (e.data.unavailable) {
|
||||
info.voiceConnection._disconnect(Errors.VOICE_CALL_UNAVAILABLE);
|
||||
} else {
|
||||
info.voiceConnection._disconnect();
|
||||
}
|
||||
}
|
||||
if (e.type === "GUILD_DELETE") {
|
||||
const info = this.getForGuild(e.data.id);
|
||||
if (!info) return;
|
||||
if (e.data.unavailable) {
|
||||
info.voiceConnection._disconnect(Errors.VOICE_GUILD_UNAVAILABLE);
|
||||
} else {
|
||||
info.voiceConnection._disconnect();
|
||||
}
|
||||
}
|
||||
if (e.type === "CHANNEL_DELETE") {
|
||||
const info = this.getForChannel(e.data.id);
|
||||
if (info) info.voiceConnection._disconnect();
|
||||
}
|
||||
});
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISCONNECT, e => {
|
||||
Array.from(this._pendingConnections.keys()).forEach(guildId => {
|
||||
var pending = this._pendingConnections.get(guildId);
|
||||
if (!pending) return;
|
||||
this._pendingConnections.delete(guildId);
|
||||
pending.reject(new Error("Gateway disconnected"));
|
||||
});
|
||||
this._gateways.delete(e.socket);
|
||||
});
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
_createPending(guildId) {
|
||||
return this._getOrCreate(guildId, null, null, null, true);
|
||||
}
|
||||
_cancelPending(guildId) {
|
||||
let pending = this._pendingConnections.get(guildId);
|
||||
if (!pending) return;
|
||||
this._pendingConnections.delete(guildId);
|
||||
pending.reject(new Error("Cancelled"));
|
||||
}
|
||||
_isPending(guildId) {
|
||||
return this._pendingConnections.get(guildId);
|
||||
}
|
||||
_getOrCreate(guildId, channelId, selfMute, selfDeaf, silent) {
|
||||
const gateway = this._discordie.gatewaySocket;
|
||||
if (!gateway || !gateway.connected)
|
||||
return Promise.reject(new Error("No gateway socket (not connected)"));
|
||||
|
||||
// voiceStateUpdate triggers some events and can update pending connections
|
||||
var newState = {guildId, channelId, selfMute, selfDeaf};
|
||||
if (!silent && this.shouldUpdateVoiceState(newState)) {
|
||||
if (!channelId && this.shouldCancelPending(guildId)) {
|
||||
this._cancelPending(guildId);
|
||||
}
|
||||
gateway.voiceStateUpdate(guildId, channelId, selfMute, selfDeaf);
|
||||
}
|
||||
|
||||
if (!silent && !channelId) return;
|
||||
|
||||
let pending = this._pendingConnections.get(guildId);
|
||||
if (pending) return pending.promise;
|
||||
|
||||
const existing = this.getForGuild(guildId);
|
||||
if (existing) return Promise.resolve(existing);
|
||||
|
||||
pending = {gateway, promise: null, resolve: null, reject: null};
|
||||
this._pendingConnections.set(guildId, pending);
|
||||
|
||||
return (pending.promise = new Promise((rs, rj) => {
|
||||
pending.resolve = rs;
|
||||
pending.reject = rj;
|
||||
}));
|
||||
}
|
||||
getForGuild(guildId) {
|
||||
guildId = guildId ? guildId.valueOf() : null;
|
||||
return this.find(c => c.voiceSocket.guildId == guildId) || null;
|
||||
}
|
||||
getForChannel(channelId) {
|
||||
channelId = channelId.valueOf();
|
||||
for (var gatewaySocket of this._gateways.values()) {
|
||||
for (var voiceState of gatewaySocket.voiceStates.values()) {
|
||||
if (!voiceState || voiceState.channelId !== channelId) continue;
|
||||
return this.getForGuild(voiceState.guildId);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
getForVoiceSocket(voiceSocket) {
|
||||
return this.find(c => c.voiceSocket == voiceSocket) || null;
|
||||
}
|
||||
getForGatewaySocket(gatewaySocket) {
|
||||
return this.find(c => c.gatewaySocket == gatewaySocket) || null;
|
||||
}
|
||||
isLocalSession(sessionId) {
|
||||
return !!Array.from(this._gateways).find(gw => gw.sessionId == sessionId);
|
||||
}
|
||||
shouldUpdateVoiceState(newState) {
|
||||
var guildId = newState.guildId;
|
||||
|
||||
for (var gatewaySocket of this._gateways.values()) {
|
||||
var state = gatewaySocket.voiceStates.get(guildId);
|
||||
if (!state) continue;
|
||||
var hasChanges = Object.keys(state).reduce((r, key) => {
|
||||
return r ||
|
||||
(newState[key] !== undefined && newState[key] != state[key]);
|
||||
}, false);
|
||||
return hasChanges;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
shouldCancelPending(guildId) {
|
||||
// cancel pending connection only if there are no sockets open
|
||||
// otherwise disconnect existing socket and fire VOICESOCKET_DISCONNECT
|
||||
for (var gatewaySocket of this._gateways.values()) {
|
||||
var socket = gatewaySocket.voiceSockets.get(guildId);
|
||||
if (!socket) continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
getPendingChannel(guildId) {
|
||||
for (var gatewaySocket of this._gateways.values()) {
|
||||
var state = gatewaySocket.voiceStates.get(guildId);
|
||||
if (!state) continue;
|
||||
return state.channelId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
cancelIfPending(guildId, channelId) {
|
||||
const pendingChannelId = this.getPendingChannel(guildId);
|
||||
if (pendingChannelId && pendingChannelId === channelId)
|
||||
this._getOrCreate(guildId, null);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VoiceConnectionCollection;
|
352
node_modules/discordie/lib/collections/VoiceStateCollection.js
generated
vendored
Normal file
352
node_modules/discordie/lib/collections/VoiceStateCollection.js
generated
vendored
Normal file
@ -0,0 +1,352 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const StatusTypes = Constants.StatusTypes;
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
const BaseCollection = require("./BaseCollection");
|
||||
|
||||
const User = require("../models/User");
|
||||
const AuthenticatedUser = require("../models/AuthenticatedUser");
|
||||
|
||||
function getUserStates(userId) {
|
||||
var states = [];
|
||||
var channels = this._channelsForUser.get(userId);
|
||||
if (!channels) return states;
|
||||
Array.from(channels).forEach(channelId => {
|
||||
var userMap = this._usersForChannel.get(channelId);
|
||||
if (!userMap || !userMap.has(userId)) return;
|
||||
states.push(userMap.get(userId));
|
||||
});
|
||||
return states;
|
||||
}
|
||||
function createChangeEvent(state, e) {
|
||||
return {
|
||||
socket: e.socket,
|
||||
user: this._discordie.Users.get(state.user_id),
|
||||
channel:
|
||||
this._discordie.Channels.get(state.channel_id) ||
|
||||
this._discordie.DirectMessageChannels.get(state.channel_id),
|
||||
channelId: state.channel_id,
|
||||
guildId: state.guild_id
|
||||
};
|
||||
}
|
||||
function emitMuteDeafUpdate(type, state, key, e) {
|
||||
var e = createChangeEvent.call(this, state, e);
|
||||
e.state = state[key];
|
||||
this._discordie.Dispatcher.emit(type, e);
|
||||
}
|
||||
function emitChanges(before, after, e) {
|
||||
if (!before.length && !after.length) return;
|
||||
var leave =
|
||||
before.filter(b => !after.find(a => a.channel_id == b.channel_id));
|
||||
var join =
|
||||
after.filter(a => !before.find(b => a.channel_id == b.channel_id));
|
||||
|
||||
var moved = leave.length === 1 && join.length === 1;
|
||||
|
||||
leave.forEach(state => {
|
||||
var event = createChangeEvent.call(this, state, e);
|
||||
event.newChannelId = moved ? join[0].channel_id : null;
|
||||
event.newGuildId = moved ? join[0].guild_id : null;
|
||||
|
||||
this._discordie.Dispatcher.emit(
|
||||
Events.VOICE_CHANNEL_LEAVE,
|
||||
event
|
||||
);
|
||||
});
|
||||
join.forEach(state => {
|
||||
this._discordie.Dispatcher.emit(
|
||||
Events.VOICE_CHANNEL_JOIN,
|
||||
createChangeEvent.call(this, state, e)
|
||||
);
|
||||
});
|
||||
|
||||
if (!leave.length && !join.length) {
|
||||
var sm = after.find(b => before.find(a => a.self_mute != b.self_mute));
|
||||
var sd = after.find(b => before.find(a => a.self_deaf != b.self_deaf));
|
||||
var m = after.find(b => before.find(a => a.mute != b.mute));
|
||||
var d = after.find(b => before.find(a => a.deaf != b.deaf));
|
||||
|
||||
var _emitMuteDeafUpdate = emitMuteDeafUpdate.bind(this);
|
||||
if (sm)_emitMuteDeafUpdate(Events.VOICE_USER_SELF_MUTE, sm, "self_mute", e);
|
||||
if (sd)_emitMuteDeafUpdate(Events.VOICE_USER_SELF_DEAF, sd, "self_deaf", e);
|
||||
if (m) _emitMuteDeafUpdate(Events.VOICE_USER_MUTE, m, "mute", e);
|
||||
if (d) _emitMuteDeafUpdate(Events.VOICE_USER_DEAF, d, "deaf", e);
|
||||
}
|
||||
}
|
||||
function shouldCalculateChanges() {
|
||||
var Dispatcher = this._discordie.Dispatcher;
|
||||
return Dispatcher.hasListeners(Events.VOICE_CHANNEL_JOIN) ||
|
||||
Dispatcher.hasListeners(Events.VOICE_CHANNEL_LEAVE) ||
|
||||
Dispatcher.hasListeners(Events.VOICE_USER_SELF_MUTE) ||
|
||||
Dispatcher.hasListeners(Events.VOICE_USER_SELF_DEAF) ||
|
||||
Dispatcher.hasListeners(Events.VOICE_USER_MUTE) ||
|
||||
Dispatcher.hasListeners(Events.VOICE_USER_DEAF);
|
||||
}
|
||||
|
||||
function getOrCreate(type, target, key) {
|
||||
const _T = target.get(key);
|
||||
const got = _T || new type();
|
||||
if (!_T) target.set(key, got);
|
||||
return got;
|
||||
}
|
||||
|
||||
function speakingDelete(userId, guildId) {
|
||||
if (guildId) {
|
||||
const info = this._discordie.VoiceConnections.getForGuild(guildId);
|
||||
if (!info) return;
|
||||
const speakingSet = this._speakingForVC.get(info.voiceConnection);
|
||||
if (speakingSet) speakingSet.delete(userId);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var speakingSet of this._speakingForVC.values()) {
|
||||
speakingSet.delete(userId);
|
||||
}
|
||||
}
|
||||
|
||||
function ssrcDelete(userId, guildId) {
|
||||
function removeFromMap(ssrcMap) {
|
||||
for (var pair of ssrcMap.entries()) {
|
||||
var ssrc = pair[0];
|
||||
var user = pair[1];
|
||||
if (user == userId) ssrcMap.delete(ssrc);
|
||||
}
|
||||
}
|
||||
|
||||
if (guildId) {
|
||||
const info = this._discordie.VoiceConnections.getForGuild(guildId);
|
||||
if (!info) return;
|
||||
const ssrcMap = this._ssrcForVC.get(info.voiceConnection);
|
||||
if (ssrcMap) removeFromMap(ssrcMap);
|
||||
return;
|
||||
}
|
||||
|
||||
for (var ssrcMap of this._ssrcForVC.values()) {
|
||||
removeFromMap(ssrcMap);
|
||||
}
|
||||
}
|
||||
|
||||
function userDelete(userId, guildId) {
|
||||
var channels = this._channelsForUser.get(userId);
|
||||
if (!channels) return;
|
||||
|
||||
for (var channelId of channels.values()) {
|
||||
var userMap = this._usersForChannel.get(channelId);
|
||||
if (!userMap) continue;
|
||||
|
||||
if (guildId) {
|
||||
var state = userMap.get(userId);
|
||||
if (state.guild_id && state.guild_id !== guildId) continue;
|
||||
}
|
||||
|
||||
userMap.delete(userId);
|
||||
channels.delete(channelId);
|
||||
|
||||
if (!userMap.size) this._usersForChannel.delete(channelId);
|
||||
if (!channels.size) this._channelsForUser.delete(userId);
|
||||
}
|
||||
}
|
||||
function channelDelete(channelId) {
|
||||
var userMap = this._usersForChannel.get(channelId);
|
||||
this._usersForChannel.delete(channelId);
|
||||
if (!userMap) return;
|
||||
|
||||
for (var state of userMap.values()) {
|
||||
var channels = this._channelsForUser.get(state.user_id);
|
||||
channels.delete(state.channel_id);
|
||||
|
||||
if (!channels.size) this._channelsForUser.delete(state.user_id);
|
||||
}
|
||||
}
|
||||
|
||||
function initializeCache() {
|
||||
this._speakingForVC = new Map(); // Map<IVoiceConnection, Map<userId, bool>>
|
||||
this._ssrcForVC = new Map(); // Map<IVoiceConnection, Map<userId, ssrc>>
|
||||
this._usersForChannel = new Map(); // Map<channelId, Map<userId, voiceState>>
|
||||
this._channelsForUser = new Map(); // Map<userId, Set<channelId>>
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data) {
|
||||
initializeCache.call(this);
|
||||
data.guilds.forEach(guild => handleGuildCreate.call(this, guild));
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildCreate(guild) {
|
||||
if (guild.unavailable) return;
|
||||
guild.voice_states.forEach(state => {
|
||||
// states in READY don't contain `guild_id`
|
||||
state.guild_id = guild.id;
|
||||
insertVoiceState.call(this, state);
|
||||
});
|
||||
}
|
||||
|
||||
function handleVoiceStateUpdateChanges(data, e) {
|
||||
// process only if we have event listeners for those events
|
||||
if (!shouldCalculateChanges.call(this)) {
|
||||
handleVoiceStateUpdate.call(this, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
var before = getUserStates.call(this, data.user_id);
|
||||
|
||||
handleVoiceStateUpdate.call(this, data);
|
||||
|
||||
var after = getUserStates.call(this, data.user_id);
|
||||
process.nextTick(() => emitChanges.call(this, before, after, e));
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleVoiceStateUpdate(data) {
|
||||
userDelete.call(this, data.user_id, data.guild_id);
|
||||
if (!data.channel_id) {
|
||||
speakingDelete.call(this, data.user_id, data.guild_id);
|
||||
ssrcDelete.call(this, data.user_id, data.guild_id);
|
||||
return true;
|
||||
}
|
||||
insertVoiceState.call(this, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
function insertVoiceState(data) {
|
||||
getOrCreate(Map, this._usersForChannel, data.channel_id)
|
||||
.set(data.user_id, data);
|
||||
getOrCreate(Set, this._channelsForUser, data.user_id)
|
||||
.add(data.channel_id);
|
||||
}
|
||||
|
||||
function handleVoiceSpeaking(data, voiceSocket) {
|
||||
const info = this._discordie.VoiceConnections.getForVoiceSocket(voiceSocket);
|
||||
if (!info) return true;
|
||||
const vc = info.voiceConnection;
|
||||
|
||||
const speakingSet = getOrCreate(Set, this._speakingForVC, vc);
|
||||
data.speaking ?
|
||||
speakingSet.add(data.user_id) :
|
||||
speakingSet.delete(data.user_id);
|
||||
|
||||
getOrCreate(Map, this._ssrcForVC, vc)
|
||||
.set(data.ssrc, data.user_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleChannelDelete(channel, e) {
|
||||
// just silently delete voice states as clients still stay connected to
|
||||
// deleted channels
|
||||
|
||||
//var userMap = this._usersForChannel.get(channel.id);
|
||||
//for (var userId of userMap.keys()) {
|
||||
// var event = createChangeEvent.call(this, {
|
||||
// user_id: userId,
|
||||
// channel_id: channel.id,
|
||||
// guild_id: channel.guild_id
|
||||
// }, e);
|
||||
// event.newChannelId = event.newGuildId = null;
|
||||
//
|
||||
// this._discordie.Dispatcher.emit(Events.VOICE_CHANNEL_LEAVE, event);
|
||||
//}
|
||||
|
||||
channelDelete.call(this, channel.id);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleGuildDelete(guild) {
|
||||
handleCleanup.call(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
function handleCleanup() {
|
||||
for (var channelId of this._usersForChannel.keys()) {
|
||||
// delete all channel states if channel is no longer in cache
|
||||
if (!this._discordie._channels.get(channelId))
|
||||
channelDelete.call(this, channelId);
|
||||
}
|
||||
}
|
||||
|
||||
function handleCallCreate(call) {
|
||||
if (!call || !call.voice_states) return true;
|
||||
call.voice_states.forEach(state => {
|
||||
state.guild_id = null;
|
||||
insertVoiceState.call(this, state);
|
||||
})
|
||||
}
|
||||
|
||||
function handleCallDelete(call) {
|
||||
if (!call || !call.channel_id) return true;
|
||||
channelDelete.call(this, call.channel_id);
|
||||
}
|
||||
|
||||
class VoiceStateCollection {
|
||||
constructor(discordie, gateway) {
|
||||
if (typeof gateway !== "function")
|
||||
throw new Error("Gateway parameter must be a function");
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen,
|
||||
GUILD_CREATE: handleGuildCreate,
|
||||
GUILD_DELETE: handleGuildDelete,
|
||||
CHANNEL_DELETE: handleChannelDelete,
|
||||
VOICE_STATE_UPDATE: handleVoiceStateUpdateChanges,
|
||||
CALL_CREATE: handleCallCreate,
|
||||
CALL_DELETE: handleCallDelete
|
||||
});
|
||||
});
|
||||
discordie.Dispatcher.on(Events.VOICE_SPEAKING, e => {
|
||||
if (handleVoiceSpeaking.call(this, e.data, e.socket))
|
||||
e.handled = true;
|
||||
|
||||
if (e.data && e.data.user_id) {
|
||||
const user = this._discordie.Users.get(e.data.user_id);
|
||||
if (user) e.user = user;
|
||||
|
||||
const info = discordie.VoiceConnections.getForVoiceSocket(e.socket);
|
||||
if (info) e.voiceConnection = info.voiceConnection;
|
||||
}
|
||||
});
|
||||
discordie.Dispatcher.on(Events.VOICE_DISCONNECTED, e => {
|
||||
this._speakingForVC.delete(e.voiceConnection);
|
||||
this._ssrcForVC.delete(e.voiceConnection);
|
||||
});
|
||||
|
||||
initializeCache.call(this);
|
||||
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
getStatesInChannel(channelId) {
|
||||
channelId = channelId.valueOf();
|
||||
const userMap = this._usersForChannel.get(channelId);
|
||||
if (!userMap) return new Map();
|
||||
return userMap;
|
||||
}
|
||||
getUserStateInGuild(guildId, userId) {
|
||||
// note: there can be more than 1 voice member with same user id in guild
|
||||
// this will return only the first voice state registered
|
||||
var channels = this._channelsForUser.get(userId);
|
||||
if (!channels) return null;
|
||||
|
||||
for (var channelId of channels.values()) {
|
||||
const userMap = this._usersForChannel.get(channelId);
|
||||
if (!userMap) continue;
|
||||
|
||||
var state = userMap.get(userId);
|
||||
if (!state) continue;
|
||||
|
||||
if (state.guild_id == guildId) return state;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
ssrcToUserId(voiceConnection, ssrc) {
|
||||
const ssrcMap = this._ssrcForVC.get(voiceConnection);
|
||||
if (ssrcMap) return ssrcMap.get(ssrc) || null;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = VoiceStateCollection;
|
168
node_modules/discordie/lib/core/ApiRequest.js
generated
vendored
Normal file
168
node_modules/discordie/lib/core/ApiRequest.js
generated
vendored
Normal file
@ -0,0 +1,168 @@
|
||||
"use strict";
|
||||
|
||||
const superagent = require("superagent");
|
||||
const Constants = require("../Constants");
|
||||
const Backoff = require("./Backoff");
|
||||
|
||||
const os = require("os");
|
||||
const version = require('../../package.json').version;
|
||||
|
||||
const useragent = process.browser ? "" : [
|
||||
"DiscordBot",
|
||||
`(https://github.com/qeled/discordie, v${version})`,
|
||||
`(${os.type()} ${os.release()}; ${os.arch()})`,
|
||||
process.version.replace(/^v/, (process.release.name || "node") + "/"),
|
||||
process.versions.openssl ? `openssl/${process.versions.openssl}` : null,
|
||||
].filter(e => e).join(" ");
|
||||
|
||||
function isDiscordAPI(url) {
|
||||
if (!url.startsWith("/")) return false;
|
||||
for (const k in Constants.Endpoints) {
|
||||
if (url.startsWith(Constants.Endpoints[k]))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const BAD_GATEWAY_MIN_DELAY_MS = 100;
|
||||
const BAD_GATEWAY_MAX_RETRIES = 10;
|
||||
|
||||
const HTTP_BAD_GATEWAY = 502;
|
||||
|
||||
class ApiRequest {
|
||||
constructor(method, discordie, options) {
|
||||
this._discordie = discordie;
|
||||
|
||||
options = options || {};
|
||||
if (typeof options === "string") {
|
||||
options = {url: options};
|
||||
}
|
||||
options.method = method;
|
||||
|
||||
if (!options.url) {
|
||||
throw new TypeError(`ApiRequest ${method} failed: Invalid URL`);
|
||||
}
|
||||
|
||||
this._badGatewayBackoff = new Backoff(
|
||||
BAD_GATEWAY_MIN_DELAY_MS,
|
||||
BAD_GATEWAY_MIN_DELAY_MS * 100
|
||||
);
|
||||
this._badGatewayRetries = 0;
|
||||
|
||||
this._options = options;
|
||||
this._request = null;
|
||||
|
||||
this._promise = null;
|
||||
this._resolve = null;
|
||||
this._reject = null;
|
||||
|
||||
this._callback = null;
|
||||
}
|
||||
get method() {
|
||||
return this._options.method;
|
||||
}
|
||||
get path() {
|
||||
return this._options.url;
|
||||
}
|
||||
send(callback) {
|
||||
if (this._promise) {
|
||||
if (callback) {
|
||||
console.warn(
|
||||
"Called ApiRequest.send with callback more than 1 time: "
|
||||
+ this._options.url
|
||||
);
|
||||
}
|
||||
return this._promise;
|
||||
}
|
||||
|
||||
this._callback = callback || null;
|
||||
|
||||
this._promise = new Promise((rs, rj) => {
|
||||
this._resolve = rs;
|
||||
this._reject = rj;
|
||||
|
||||
this._send();
|
||||
});
|
||||
|
||||
// no need to fire unhandled rejection for this one if using callback
|
||||
if (callback) {
|
||||
this._promise.catch(this._void);
|
||||
}
|
||||
|
||||
return this._promise;
|
||||
}
|
||||
_void() {}
|
||||
_safeCallback(err, res) {
|
||||
if (typeof this._callback !== "function") return;
|
||||
this._callback(err, res);
|
||||
this._callback = null;
|
||||
}
|
||||
_send() {
|
||||
const token = this._discordie.token;
|
||||
const method = this._options.method;
|
||||
const query = this._options.query;
|
||||
const body = this._options.body;
|
||||
const attachDelegate = this._options.attachDelegate;
|
||||
const rs = this._resolve, rj = this._reject;
|
||||
|
||||
var req = superagent[method](Constants.API_ENDPOINT + this._options.url);
|
||||
this._request = req;
|
||||
|
||||
const botPrefix = this._discordie.bot ? "Bot " : "";
|
||||
|
||||
if (useragent) req.set("User-Agent", useragent);
|
||||
if (token) req.set("Authorization", botPrefix + token);
|
||||
if (query) req.query(query);
|
||||
if (body) req.send(body);
|
||||
|
||||
if (typeof attachDelegate === "function") attachDelegate(req);
|
||||
// warning: don't call requests with attachDelegate more than once because
|
||||
// it can attach form data with streams
|
||||
|
||||
req.end((err, res) => {
|
||||
this._request = null;
|
||||
|
||||
if (res && !res.ok && res.status === HTTP_BAD_GATEWAY) {
|
||||
this._badGatewayRetries++;
|
||||
if (this._badGatewayRetries <= BAD_GATEWAY_MAX_RETRIES) {
|
||||
return this._badGatewayBackoff.fail(() => this._send());
|
||||
}
|
||||
}
|
||||
|
||||
if (err || !res.ok) {
|
||||
if (res && res.body && res.body.code && res.body.message) {
|
||||
err.code = res.body.code;
|
||||
err.message = err.message + ` (${res.body.message})`;
|
||||
}
|
||||
rj(err);
|
||||
} else {
|
||||
rs(res);
|
||||
}
|
||||
|
||||
this._promise = null;
|
||||
this._safeCallback(err, res);
|
||||
});
|
||||
|
||||
req.on("abort", () => {
|
||||
this._request = null;
|
||||
rj("Cancelled");
|
||||
});
|
||||
}
|
||||
cancel() {
|
||||
if (!this._request) return;
|
||||
this._request.abort();
|
||||
}
|
||||
}
|
||||
|
||||
function createRequest(_method, discordie, options) {
|
||||
return new ApiRequest(_method, discordie, options);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
get: createRequest.bind(null, "get"),
|
||||
post: createRequest.bind(null, "post"),
|
||||
patch: createRequest.bind(null, "patch"),
|
||||
put: createRequest.bind(null, "put"),
|
||||
del: createRequest.bind(null, "del"),
|
||||
delete: createRequest.bind(null, "del")
|
||||
};
|
56
node_modules/discordie/lib/core/Backoff.js
generated
vendored
Normal file
56
node_modules/discordie/lib/core/Backoff.js
generated
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
"use strict";
|
||||
|
||||
class Backoff {
|
||||
constructor(min, max, jitter) {
|
||||
this._min = (min != null && min > 0) ? min : 500;
|
||||
this._max = (max != null && max > this._min) ? max : (this._min * 30);
|
||||
this.jitter = (jitter != null) ? jitter : true;
|
||||
|
||||
this.fails = 0;
|
||||
this.delay = this._min;
|
||||
|
||||
this._timer = null;
|
||||
}
|
||||
|
||||
get min() { return this._min; }
|
||||
set min(value) {
|
||||
if (value < 0) throw new TypeError("Param 'value' must be >= 0");
|
||||
this._min = value;
|
||||
if (!this.fails) this.delay = this._min;
|
||||
}
|
||||
|
||||
get max() { return this._max; }
|
||||
set max(value) {
|
||||
if (value < 5000) throw new TypeError("Param 'value' must be >= 5000");
|
||||
this._max = value;
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.cancel();
|
||||
this.fails = 0;
|
||||
this.delay = this._min;
|
||||
}
|
||||
fail(cb) {
|
||||
this.fails++;
|
||||
const delay = this.delay * 2 * (this.jitter ? Math.random() : 1);
|
||||
this.delay = Math.min(this.delay + delay, this._max);
|
||||
|
||||
if (typeof cb !== "function") return this.delay;
|
||||
|
||||
this.cancel();
|
||||
this._timer = setTimeout(() => {
|
||||
try { cb(); }
|
||||
catch (e) { console.log(e instanceof Error ? e.stack : e); }
|
||||
finally { this._timer = null; }
|
||||
}, this.delay);
|
||||
|
||||
return this.delay;
|
||||
}
|
||||
cancel() {
|
||||
if (!this._timer) return;
|
||||
clearTimeout(this._timer);
|
||||
this._timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Backoff;
|
52
node_modules/discordie/lib/core/DiscordieDispatcher.js
generated
vendored
Normal file
52
node_modules/discordie/lib/core/DiscordieDispatcher.js
generated
vendored
Normal file
@ -0,0 +1,52 @@
|
||||
"use strict";
|
||||
|
||||
const DiscordieError = require("./DiscordieError");
|
||||
const Constants = require("../Constants");
|
||||
const EventTypes = Object.keys(Constants.Events);
|
||||
|
||||
const events = require("events");
|
||||
|
||||
let lastEvent = null;
|
||||
|
||||
function validateEvent(eventType) {
|
||||
if (EventTypes.indexOf(eventType) < 0)
|
||||
throw new DiscordieError(`Invalid event '${eventType}'`);
|
||||
}
|
||||
|
||||
class DiscordieDispatcher extends events.EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this._anyeventlisteners = [];
|
||||
this.setMaxListeners(14);
|
||||
}
|
||||
static _getLastEvent() { return lastEvent; }
|
||||
on(eventType, listener) {
|
||||
validateEvent(eventType);
|
||||
return super.on.apply(this, arguments);
|
||||
}
|
||||
onAny(fn) {
|
||||
if (typeof fn !== "function")
|
||||
return this;
|
||||
this._anyeventlisteners.push(fn);
|
||||
return this;
|
||||
}
|
||||
emit(eventType) {
|
||||
validateEvent(eventType);
|
||||
|
||||
lastEvent = [].slice.call(arguments);
|
||||
super.emit.apply(this, arguments);
|
||||
const _arguments = arguments;
|
||||
this._anyeventlisteners.forEach((fn) => {
|
||||
fn.apply(this, _arguments);
|
||||
});
|
||||
}
|
||||
hasListeners(eventType) {
|
||||
validateEvent(eventType);
|
||||
|
||||
if (this._anyeventlisteners.length || this.listenerCount(eventType))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DiscordieDispatcher;
|
13
node_modules/discordie/lib/core/DiscordieError.js
generated
vendored
Normal file
13
node_modules/discordie/lib/core/DiscordieError.js
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
"use strict";
|
||||
|
||||
class DiscordieError extends Error {
|
||||
constructor(message, exception) {
|
||||
super(message);
|
||||
if (exception) this.exception = exception;
|
||||
}
|
||||
toJSON() {
|
||||
return this.message;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DiscordieError;
|
24
node_modules/discordie/lib/core/DiscordieProfiler.js
generated
vendored
Normal file
24
node_modules/discordie/lib/core/DiscordieProfiler.js
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
const state = new Map();
|
||||
const stats = new Map();
|
||||
|
||||
class DiscordieProfiler {
|
||||
static hrtime() {
|
||||
const t = process.hrtime();
|
||||
return t[0] * 1000 + t[1] / 1000000;
|
||||
}
|
||||
static start(n) {
|
||||
state.set(n, this.hrtime());
|
||||
}
|
||||
static stop(n) {
|
||||
const d = this.hrtime() - state.get(n);
|
||||
stats.set(n, d);
|
||||
return d;
|
||||
}
|
||||
static get(n) {
|
||||
return stats.get(n);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DiscordieProfiler;
|
71
node_modules/discordie/lib/core/GatewayReconnectHandler.js
generated
vendored
Normal file
71
node_modules/discordie/lib/core/GatewayReconnectHandler.js
generated
vendored
Normal file
@ -0,0 +1,71 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Backoff = require("./Backoff");
|
||||
|
||||
/**
|
||||
* @class
|
||||
*/
|
||||
class GatewayReconnectHandler {
|
||||
constructor(discordie) {
|
||||
this._discordie = discordie;
|
||||
this._backoff = new Backoff(1000, 60000);
|
||||
this._enabled = false;
|
||||
}
|
||||
|
||||
_disconnected(e) {
|
||||
if (!this._enabled) return;
|
||||
e.autoReconnect = true;
|
||||
e.delay = this._backoff.fail(() => this._discordie.connect());
|
||||
}
|
||||
|
||||
_reset() {
|
||||
this._backoff.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables auto-reconnect.
|
||||
*/
|
||||
enable() { this._enabled = true; }
|
||||
|
||||
/**
|
||||
* Disables auto-reconnect.
|
||||
*/
|
||||
disable() { this._enabled = false; }
|
||||
|
||||
/**
|
||||
* Boolean indicating whether auto-reconnect is enabled.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get enabled() { return this._enabled; }
|
||||
|
||||
/**
|
||||
* Gets/sets minimum delay in milliseconds. Must be >= 0.
|
||||
*
|
||||
* Default is 1000.
|
||||
* @returns {Number}
|
||||
*/
|
||||
get min() { return this._backoff.min; }
|
||||
/**
|
||||
* @ignore
|
||||
* @type {Number}
|
||||
**/
|
||||
set min(value) { this._backoff.min = value; }
|
||||
|
||||
/**
|
||||
* Gets/sets maximum delay in milliseconds. Must be >= 5000.
|
||||
*
|
||||
* Default is 60000.
|
||||
* @returns {Number}
|
||||
*/
|
||||
get max() { return this._backoff.max; }
|
||||
/**
|
||||
* @ignore
|
||||
* @type {Number}
|
||||
**/
|
||||
set max(value) { this._backoff.max = value; }
|
||||
}
|
||||
|
||||
module.exports = GatewayReconnectHandler;
|
93
node_modules/discordie/lib/core/LimitedCache.js
generated
vendored
Normal file
93
node_modules/discordie/lib/core/LimitedCache.js
generated
vendored
Normal file
@ -0,0 +1,93 @@
|
||||
"use strict";
|
||||
|
||||
function findKeyInsertionPoint(array, element, start, end) {
|
||||
if (start === undefined) start = 0;
|
||||
if (end === undefined) end = array.length;
|
||||
|
||||
var min = start, max = end;
|
||||
while (true) {
|
||||
var k = ((min + max) / 2) | 0;
|
||||
if (k > end || min === max) break;
|
||||
|
||||
var result = (+element) - (+array[k]);
|
||||
if (result === 0) break;
|
||||
else if (result > 0) min = k + 1;
|
||||
else if (result < 0) max = k;
|
||||
}
|
||||
|
||||
return k;
|
||||
}
|
||||
|
||||
class LimitedCache {
|
||||
constructor(limit) {
|
||||
this._keys = [];
|
||||
Object.defineProperty(this, "_keys", { enumerable: false });
|
||||
this._map = new Map;
|
||||
this.setLimit(limit);
|
||||
}
|
||||
setLimit(limit) {
|
||||
this.limit = limit || 1000;
|
||||
if (!(this.limit > 0)) this.limit = 1;
|
||||
return this.trim();
|
||||
}
|
||||
trim() {
|
||||
var keys = this._keys;
|
||||
if (keys.length <= this.limit) return null;
|
||||
var removed = keys.splice(0, keys.length - this.limit);
|
||||
for (var i = 0; i < removed.length; i++)
|
||||
this._map.delete(removed[i]);
|
||||
return removed;
|
||||
}
|
||||
set(k, v) {
|
||||
if (!this._map.has(k)) {
|
||||
this._keys.splice(findKeyInsertionPoint(this._keys, k), 0, k);
|
||||
this.trim();
|
||||
}
|
||||
return this._map.set(k, v);
|
||||
}
|
||||
rename(from, to) {
|
||||
var i = this._keys.indexOf(from);
|
||||
if (i >= 0) {
|
||||
this._keys.splice(i, 1);
|
||||
this._keys.splice(findKeyInsertionPoint(this._keys, to), 0, to);
|
||||
}
|
||||
if (this._map.has(from)) {
|
||||
this._map.set(to, this._map.get(from));
|
||||
this._map.delete(from);
|
||||
}
|
||||
}
|
||||
delete(k) {
|
||||
if (this._map.delete(k)) {
|
||||
var i = this._keys.indexOf(k);
|
||||
if (i >= 0) this._keys.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
clear() {
|
||||
this._keys.length = 0;
|
||||
return this._map.clear();
|
||||
}
|
||||
forEach(fn) { return this._map.forEach(fn); }
|
||||
values() { return this._map.values(); }
|
||||
entries() { return this._map.entries(); }
|
||||
keys() { return this._map.keys(); }
|
||||
get(k) { return this._map.get(k); }
|
||||
has(k) { return this._map.has(k); }
|
||||
get size() { return this._map.size; }
|
||||
|
||||
map(fn) {
|
||||
if (typeof fn !== "function") {
|
||||
throw new TypeError("fn is not a function");
|
||||
}
|
||||
if (!this._keys.length) return [];
|
||||
var items = [];
|
||||
for (var i = 0, len = this._keys.length; i < len; i++) {
|
||||
var item = this.get(this._keys[i]);
|
||||
items.push(fn(item));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = LimitedCache;
|
59
node_modules/discordie/lib/core/MessageHandlerCache.js
generated
vendored
Normal file
59
node_modules/discordie/lib/core/MessageHandlerCache.js
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
|
||||
const discordie = new WeakMap();
|
||||
|
||||
const messageHandlerCache = {};
|
||||
function processMessage(source, socket, type, data) {
|
||||
if (messageHandlerCache[`${source}/${type}`]) {
|
||||
if (typeof messageHandlerCache[`${source}/${type}`] === "function")
|
||||
return messageHandlerCache[`${source}/${type}`].apply(this, [data, socket]);
|
||||
return false;
|
||||
}
|
||||
|
||||
let messageHandler = null;
|
||||
|
||||
if (process.browser) {
|
||||
const ctx = require.context("../networking/messages/", true, /\.js$/);
|
||||
const modulePath = `./${source}/${type.toLowerCase()}.js`;
|
||||
|
||||
try {
|
||||
messageHandler = ctx(modulePath);
|
||||
} catch (e) { } //eslint-disable-line no-empty
|
||||
} else {
|
||||
const modulePath =
|
||||
`../networking/messages/${source}/${type.toLowerCase()}`;
|
||||
|
||||
try {
|
||||
messageHandler = require(modulePath);
|
||||
} catch (e) {
|
||||
if (e.code != "MODULE_NOT_FOUND")
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
if (messageHandler) {
|
||||
messageHandlerCache[`${source}/${type}`] = messageHandler;
|
||||
return processMessage.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
class MessageHandlerCache {
|
||||
constructor(_discordie) {
|
||||
discordie.set(this, _discordie);
|
||||
}
|
||||
|
||||
processVoiceMessage(socket, type, data) {
|
||||
return processMessage.call(discordie.get(this),
|
||||
"voice", socket, type, data
|
||||
);
|
||||
}
|
||||
processGatewayMessage(socket, type, data) {
|
||||
return processMessage.call(discordie.get(this),
|
||||
"gateway", socket, type, data
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MessageHandlerCache;
|
106
node_modules/discordie/lib/core/ReadyEventScheduler.js
generated
vendored
Normal file
106
node_modules/discordie/lib/core/ReadyEventScheduler.js
generated
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
function emitReady(gw) {
|
||||
const ready = this._readyPayload;
|
||||
|
||||
if (!this._readyPayload) return;
|
||||
this._readyPayload = null;
|
||||
|
||||
if (!this._discordie.connected) return;
|
||||
|
||||
if (gw.isPrimary) {
|
||||
this._discordie.Dispatcher.emit(Events.GATEWAY_READY, {
|
||||
socket: gw,
|
||||
data: ready
|
||||
});
|
||||
}
|
||||
this._discordie.Dispatcher.emit(Events.ANY_GATEWAY_READY, {
|
||||
socket: gw,
|
||||
data: ready
|
||||
});
|
||||
}
|
||||
|
||||
function handleConnectionOpen(data, e) {
|
||||
this._readyPayload = data;
|
||||
this._collections = new Set(this._registeredCollections);
|
||||
this._tasks = Array.from(this._registeredTasks);
|
||||
return true;
|
||||
}
|
||||
|
||||
function executeNextTask(gw) {
|
||||
if (!this._readyPayload || !this._tasks.length) return;
|
||||
const nextTask = this._tasks.shift();
|
||||
nextTask.handler._executeReadyTask(this._readyPayload, gw);
|
||||
}
|
||||
|
||||
class ReadyEventScheduler {
|
||||
constructor(discordie, gateway) {
|
||||
this._discordie = discordie;
|
||||
|
||||
this._readyPayload = null;
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
Utils.bindGatewayEventHandlers(this, e, {
|
||||
READY: handleConnectionOpen
|
||||
});
|
||||
});
|
||||
|
||||
discordie.Dispatcher.on(Events.GATEWAY_DISCONNECT, e => {
|
||||
if (e.socket != gateway()) return;
|
||||
|
||||
this._readyPayload = null;
|
||||
});
|
||||
|
||||
// parallel
|
||||
|
||||
this._registeredCollections = new Set();
|
||||
this._collections = new Set();
|
||||
discordie.Dispatcher.on(Events.COLLECTION_READY, e => {
|
||||
this._collections.delete(e.collection);
|
||||
if (this._collections.size) return;
|
||||
|
||||
executeNextTask.call(this, gateway());
|
||||
});
|
||||
|
||||
// sequential
|
||||
|
||||
this._registeredTasks = [];
|
||||
this._tasks = [];
|
||||
discordie.Dispatcher.on(Events.READY_TASK_FINISHED, lastTask => {
|
||||
const idx = this._tasks.findIndex(t => t.handler === lastTask.handler);
|
||||
this._tasks.splice(idx, 1);
|
||||
|
||||
if (!this._tasks.length) {
|
||||
return setImmediate(() => emitReady.call(this, gateway()));
|
||||
}
|
||||
|
||||
executeNextTask.call(this, gateway());
|
||||
});
|
||||
|
||||
Utils.privatify(this);
|
||||
}
|
||||
_waitFor(collection) {
|
||||
this._registeredCollections.add(collection);
|
||||
}
|
||||
_addTask(name, handler) {
|
||||
if (typeof name !== "string") {
|
||||
throw new TypeError(
|
||||
"ReadyEventScheduler: Invalid task name " + name
|
||||
);
|
||||
}
|
||||
if (typeof handler._executeReadyTask !== "function") {
|
||||
throw new TypeError(
|
||||
"ReadyEventScheduler: Invalid handler for task " + name
|
||||
);
|
||||
}
|
||||
this._registeredTasks.push({name, handler});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReadyEventScheduler;
|
154
node_modules/discordie/lib/core/Utils.js
generated
vendored
Normal file
154
node_modules/discordie/lib/core/Utils.js
generated
vendored
Normal file
@ -0,0 +1,154 @@
|
||||
"use strict";
|
||||
|
||||
const Stream = require("stream").Stream;
|
||||
const Writable = require("stream").Writable;
|
||||
class CachingSink extends Writable {
|
||||
constructor() {
|
||||
super();
|
||||
this.buffer = [];
|
||||
}
|
||||
_write(chunk, encoding, done) {
|
||||
this.buffer.push(chunk);
|
||||
done();
|
||||
}
|
||||
getData() { return Buffer.concat(this.buffer); }
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
allocBuffer(size) {
|
||||
return Buffer.alloc ? Buffer.alloc(size) : new Buffer(size);
|
||||
},
|
||||
createArrayBuffer(source) {
|
||||
var view = new Uint8Array(new ArrayBuffer(source.length));
|
||||
for (var i = 0; i < view.length; i++)
|
||||
view[i] = source[i];
|
||||
return view.buffer;
|
||||
},
|
||||
createBuffer(source) {
|
||||
if (source instanceof Float32Array) {
|
||||
var buf = this.allocBuffer(source.length * 4);
|
||||
for (var i = 0; i < source.length; i++) {
|
||||
buf.writeFloatLE(source[i], i * 4);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
var view = new Uint8Array(source);
|
||||
var buf = this.allocBuffer(view.length);
|
||||
for (var i = 0; i < view.length; i++)
|
||||
buf[i] = view[i];
|
||||
return buf;
|
||||
},
|
||||
bindGatewayEventHandlers(source, event, map) {
|
||||
if (!event.type)
|
||||
throw new Error(`Invalid event '${event.type}'`);
|
||||
|
||||
let handler = map[event.type];
|
||||
if (!handler) return;
|
||||
|
||||
if (typeof handler !== "function")
|
||||
throw new Error(`Invalid handler ${handler} for event ${event.type}`);
|
||||
|
||||
if (handler.call(source, event.data, event))
|
||||
event.handled = true;
|
||||
},
|
||||
privatify(target) {
|
||||
for (var k in target) {
|
||||
if (k.charCodeAt(0) != 95) // "_"
|
||||
continue;
|
||||
if (!target.hasOwnProperty(k)) continue;
|
||||
Object.defineProperty(target, k, {enumerable: false});
|
||||
}
|
||||
},
|
||||
definePrivate(target, kv) {
|
||||
for (var k in kv) {
|
||||
Object.defineProperty(target, k, {
|
||||
enumberable: false,
|
||||
writable: true,
|
||||
value: kv[k]
|
||||
});
|
||||
}
|
||||
},
|
||||
reorderObjects(array, target, position) {
|
||||
array = array.slice();
|
||||
array.sort((a, b) => (a.position - b.position));
|
||||
const from = Math.max(array.findIndex(c => (c.id == target.id)), 0);
|
||||
const to = Math.min(Math.max(position, 0), array.length - 1);
|
||||
|
||||
if (from == to) return;
|
||||
|
||||
const remove = (i) => array.splice(i, 1)[0];
|
||||
const insert = (i, v) => array.splice(i, 0, v);
|
||||
|
||||
insert(to, remove(from));
|
||||
|
||||
const updated = array.map((c, i) => ({id: c.valueOf(), position: i}));
|
||||
const changes = to > from ?
|
||||
updated.slice(from, to + 1) :
|
||||
updated.slice(to, from + 1);
|
||||
|
||||
return changes;
|
||||
},
|
||||
imageToDataURL(buffer) {
|
||||
if (!buffer || !(buffer instanceof Buffer)) return null;
|
||||
|
||||
const types = {
|
||||
0xFFD8FF: "image/jpg",
|
||||
0x89504E: "image/png"
|
||||
};
|
||||
|
||||
const magic = buffer.readUIntBE(0, 3);
|
||||
const type = types[magic];
|
||||
if (!type) return null;
|
||||
|
||||
return `data:${type};base64,` + buffer.toString("base64");
|
||||
},
|
||||
timestampFromSnowflake(id) {
|
||||
return id ? (+id / 4194304) + 1420070400000 : 0;
|
||||
},
|
||||
convertMentions(mentions) {
|
||||
if (!mentions) return mentions;
|
||||
if (mentions.map) return mentions.map(m => m.valueOf());
|
||||
return [mentions.valueOf()];
|
||||
},
|
||||
fileExists(path) {
|
||||
try {
|
||||
return require("fs").statSync(path).isFile();
|
||||
} catch (e) { return false; }
|
||||
},
|
||||
modelToObject(model) {
|
||||
if (typeof model !== "object") return model;
|
||||
if (Array.isArray(model)) {
|
||||
return Array.from(model).map(i => this.modelToObject(i));
|
||||
}
|
||||
|
||||
const copy = Object.assign({}, model);
|
||||
|
||||
Object.keys(copy).forEach(k => {
|
||||
var v = copy[k];
|
||||
const type = v && v.constructor && v.constructor.name;
|
||||
if (type === "Object") copy[k] = this.modelToObject(v);
|
||||
if (type === "Array") v = copy[k] = Array.from(v);
|
||||
if (type === "Set") v = copy[k] = Array.from(v);
|
||||
if (type === "Map") v = copy[k] = Array.from(v.values());
|
||||
if (Array.isArray(v)) copy[k] = v.map(i => this.modelToObject(i));
|
||||
});
|
||||
|
||||
return copy;
|
||||
},
|
||||
cacheStream(stream, cb) {
|
||||
if (stream instanceof Stream &&
|
||||
typeof stream._read === "function" &&
|
||||
typeof stream.pipe === "function") {
|
||||
const sink = new CachingSink();
|
||||
sink.on("finish", () => cb(sink.getData()));
|
||||
stream.pipe(sink);
|
||||
return;
|
||||
}
|
||||
cb(stream);
|
||||
},
|
||||
emojiToCode(emoji) {
|
||||
if (typeof emoji === "string") return emoji;
|
||||
return emoji.id != null ? `${emoji.name}:${emoji.id}` : emoji.name;
|
||||
}
|
||||
};
|
54
node_modules/discordie/lib/core/ratelimiting/Bucket.js
generated
vendored
Normal file
54
node_modules/discordie/lib/core/ratelimiting/Bucket.js
generated
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
"use strict";
|
||||
|
||||
const Profiler = require("../DiscordieProfiler");
|
||||
|
||||
class Bucket {
|
||||
constructor(size, duration) {
|
||||
this.size = size;
|
||||
this.duration = duration;
|
||||
|
||||
if (typeof size !== "number")
|
||||
throw new TypeError("Param 'size' is not a number");
|
||||
if (typeof duration !== "number")
|
||||
throw new TypeError("Param 'duration' is not a number");
|
||||
|
||||
this.refill();
|
||||
}
|
||||
resize(newSize) {
|
||||
if (newSize > 0) {
|
||||
if (this.size === this.dropsLeft) this.dropsLeft = newSize;
|
||||
if ((this.size - 1) === this.dropsLeft) this.dropsLeft = newSize - 1;
|
||||
}
|
||||
this.size = newSize;
|
||||
}
|
||||
rescheduleRefill(timeFromNow) {
|
||||
this.lastRefill = (Profiler.hrtime() - this.duration) + timeFromNow;
|
||||
}
|
||||
wait(time) {
|
||||
this.rescheduleRefill(time);
|
||||
this.dropsLeft = 0;
|
||||
}
|
||||
refill() {
|
||||
this.lastRefill = Profiler.hrtime();
|
||||
this.dropsLeft = this.size;
|
||||
}
|
||||
get waitTime() {
|
||||
var now = Profiler.hrtime();
|
||||
return (this.lastRefill + this.duration) - now;
|
||||
}
|
||||
get available() {
|
||||
if (this.waitTime < 0)
|
||||
this.refill();
|
||||
return this.dropsLeft;
|
||||
}
|
||||
consume(n) {
|
||||
if (!n) n = 1;
|
||||
if (this.available < n)
|
||||
return false;
|
||||
|
||||
this.dropsLeft -= n;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Bucket;
|
39
node_modules/discordie/lib/core/ratelimiting/ChainedBucket.js
generated
vendored
Normal file
39
node_modules/discordie/lib/core/ratelimiting/ChainedBucket.js
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
|
||||
const Bucket = require("./Bucket");
|
||||
|
||||
class ChainedBucket extends Bucket {
|
||||
constructor(size, duration, name, parent) {
|
||||
super(size, duration);
|
||||
this.parent = parent || null;
|
||||
this.name = name || null;
|
||||
}
|
||||
refillByName(name) {
|
||||
if (this.parent) this.parent.refillByName(name);
|
||||
if (this.name && this.name.indexOf(name) === 0) this.refill();
|
||||
}
|
||||
get waitingBucket() {
|
||||
if (this.parent && this.parent.available <= 0)
|
||||
return this.parent;
|
||||
if (this.available <= 0)
|
||||
return this;
|
||||
return null;
|
||||
}
|
||||
get available() {
|
||||
// this getter triggers refill
|
||||
const availableParent = this.parent && this.parent.available;
|
||||
const availableSelf = super.available;
|
||||
if (this.parent && availableParent <= 0)
|
||||
return availableParent;
|
||||
return availableSelf;
|
||||
}
|
||||
consume(n) {
|
||||
// this triggers 'available' getter which triggers refill
|
||||
if (this.parent) {
|
||||
return super.consume(n) && this.parent.consume(n);
|
||||
}
|
||||
return super.consume(n);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ChainedBucket;
|
128
node_modules/discordie/lib/core/ratelimiting/RequestQueue.js
generated
vendored
Normal file
128
node_modules/discordie/lib/core/ratelimiting/RequestQueue.js
generated
vendored
Normal file
@ -0,0 +1,128 @@
|
||||
"use strict";
|
||||
|
||||
const Deque = require("double-ended-queue");
|
||||
|
||||
const DEFAULT_RETRY_AFTER = 100;
|
||||
|
||||
const POST_RATELIMIT_DELAY = 1000;
|
||||
|
||||
class RequestQueue {
|
||||
constructor(bucket) {
|
||||
this.bucket = bucket || null;
|
||||
|
||||
this.queue = new Deque();
|
||||
this.timeout = null;
|
||||
this.draining = false;
|
||||
|
||||
this.lastReset = 0;
|
||||
|
||||
this.disabled = false;
|
||||
}
|
||||
enqueue(request, sendCallback) {
|
||||
this.queue.push({request, sendCallback});
|
||||
this._drain();
|
||||
}
|
||||
_drain() {
|
||||
if (this.disabled) {
|
||||
const entry = this.queue.shift();
|
||||
entry.request.send(entry.sendCallback);
|
||||
if (this.queue.length) {
|
||||
setImmediate(() => this._drain());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.queue.length) return;
|
||||
if (this.timeout !== null || this.draining) return;
|
||||
|
||||
if (this.bucket && !this.bucket.consume()) {
|
||||
this._scheduleDrain(this.bucket.waitTime);
|
||||
return;
|
||||
}
|
||||
|
||||
this.draining = true;
|
||||
const entry = this.queue.shift();
|
||||
|
||||
entry.request.send((err, res) => {
|
||||
this.draining = false;
|
||||
|
||||
this._updateBucket(res);
|
||||
|
||||
if (err && res && res.status === 429) {
|
||||
this.queue.unshift(entry);
|
||||
|
||||
const retryAfter =
|
||||
res.body["retry_after"] ||
|
||||
(+res.headers["retry-after"]) ||
|
||||
DEFAULT_RETRY_AFTER;
|
||||
|
||||
const isGlobal =
|
||||
res.body["global"] ||
|
||||
(res.headers["x-ratelimit-global"] === "true") ||
|
||||
false;
|
||||
|
||||
if (isGlobal) {
|
||||
const manager = entry.request._discordie._queueManager;
|
||||
if (manager && manager.globalBucket) {
|
||||
manager.globalBucket.wait(retryAfter);
|
||||
}
|
||||
} else if (this.bucket) {
|
||||
this.bucket.wait(retryAfter);
|
||||
}
|
||||
|
||||
this._scheduleDrain(retryAfter);
|
||||
return;
|
||||
}
|
||||
|
||||
setImmediate(() => this._drain());
|
||||
if (typeof entry.sendCallback === "function") {
|
||||
entry.sendCallback(err, res);
|
||||
}
|
||||
});
|
||||
}
|
||||
_updateBucket(res) {
|
||||
if (!res || !res.headers) return;
|
||||
if (!this.bucket) return;
|
||||
|
||||
// update limits and timing based on server info if available,
|
||||
// otherwise fallback to hardcoded buckets
|
||||
|
||||
// each window is delayed by POST_RATELIMIT_DELAY = 1s:
|
||||
// this makes it slower, but ensures not hitting 429 unless:
|
||||
// - some other client has drained all tokens already,
|
||||
// - server time is out of sync by more than 1 second,
|
||||
// - or headers X-RateLimit-Reset/Date do not contain usable time
|
||||
|
||||
if (res.headers["x-ratelimit-limit"]) {
|
||||
const limit = +res.headers["x-ratelimit-limit"];
|
||||
if (limit > 0) this.bucket.resize(limit);
|
||||
}
|
||||
|
||||
if (res.headers["x-ratelimit-remaining"]) {
|
||||
const remaining = +res.headers["x-ratelimit-remaining"];
|
||||
if (!isNaN(remaining)) this.bucket.dropsLeft = remaining;
|
||||
}
|
||||
|
||||
if (res.headers["x-ratelimit-reset"] && res.headers["date"]) {
|
||||
const resetSeconds = (+res.headers["x-ratelimit-reset"]) || 0;
|
||||
if (resetSeconds > 0) {
|
||||
const date = new Date(res.headers["date"]).getTime();
|
||||
const reset = new Date(resetSeconds * 1000).getTime();
|
||||
const now = date > 0 ? date : Date.now();
|
||||
|
||||
if (!this.lastReset || reset > this.lastReset) {
|
||||
this.lastReset = reset;
|
||||
this.bucket.rescheduleRefill(reset - now);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_scheduleDrain(time) {
|
||||
this.timeout = setTimeout(() => {
|
||||
this.timeout = null;
|
||||
this._drain();
|
||||
}, time + POST_RATELIMIT_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RequestQueue;
|
256
node_modules/discordie/lib/core/ratelimiting/RequestQueueManager.js
generated
vendored
Normal file
256
node_modules/discordie/lib/core/ratelimiting/RequestQueueManager.js
generated
vendored
Normal file
@ -0,0 +1,256 @@
|
||||
"use strict";
|
||||
|
||||
const Utils = require("../../core/Utils");
|
||||
const RequestQueue = require("./RequestQueue");
|
||||
|
||||
const ChainedBucket = require("./ChainedBucket");
|
||||
|
||||
class RequestQueueGroup {
|
||||
constructor(bucketFactory) {
|
||||
this.queues = {};
|
||||
this.bucketFactory = bucketFactory || null;
|
||||
|
||||
if (!(bucketFactory instanceof BucketFactory)) {
|
||||
throw new TypeError(
|
||||
"Param 'bucketFactory' is not an instance of BucketFactory"
|
||||
);
|
||||
}
|
||||
}
|
||||
get(id) {
|
||||
if (!this.queues[id]) {
|
||||
const bucket = (this.bucketFactory && this.bucketFactory.get(id));
|
||||
this.queues[id] = new RequestQueue(bucket);
|
||||
}
|
||||
this.queues[id].id = id;
|
||||
return this.queues[id];
|
||||
}
|
||||
delete(id) {
|
||||
if (this.bucketFactory)
|
||||
this.bucketFactory.delete(id);
|
||||
delete this.queues[id];
|
||||
}
|
||||
deleteContaining(id) {
|
||||
var keys = Object.keys(this.queues);
|
||||
for (var i = 0, len = keys.length; i < len; i++) {
|
||||
var key = keys[i];
|
||||
if (!key || key.indexOf(id) < 0) continue;
|
||||
this.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BucketFactory {
|
||||
constructor(manager, size, duration, name, parent) {
|
||||
this.manager = manager;
|
||||
this.size = size;
|
||||
this.duration = duration;
|
||||
this.name = name;
|
||||
this.parent = parent || null;
|
||||
|
||||
if (!(manager instanceof RequestQueueManager))
|
||||
throw new TypeError("Param 'manager' is invalid");
|
||||
if (typeof size !== "number")
|
||||
throw new TypeError("Param 'size' is not a number");
|
||||
if (typeof duration !== "number")
|
||||
throw new TypeError("Param 'duration' is not a number");
|
||||
if (typeof name !== "string")
|
||||
throw new TypeError("Param 'name' is not a string");
|
||||
}
|
||||
makeName(id) {
|
||||
return this.name + ":" + id;
|
||||
}
|
||||
get(id) {
|
||||
const parent =
|
||||
this.parent instanceof BucketFactory ?
|
||||
this.parent.get(id) :
|
||||
this.parent;
|
||||
return this.manager._createBucket(
|
||||
this.size, this.duration, this.makeName(id), parent
|
||||
);
|
||||
}
|
||||
delete(id) {
|
||||
delete this.manager.buckets[this.makeName(id)];
|
||||
}
|
||||
}
|
||||
|
||||
class RequestQueueManager {
|
||||
constructor(discordie) {
|
||||
this._discordie = discordie;
|
||||
|
||||
this.isBot = true;
|
||||
|
||||
this.disabled = false;
|
||||
|
||||
this.buckets = {};
|
||||
this.bucketFactories = {};
|
||||
|
||||
// whole API, bucket blocks when client gets a HTTP 429 with global flag
|
||||
const _bot_global =
|
||||
this._createBucket(Infinity, 1000, "bot:global");
|
||||
|
||||
this.globalBucket = _bot_global;
|
||||
|
||||
// msg 10/10s
|
||||
const _msg =
|
||||
this._createBucket(10, 10000, "msg", _bot_global);
|
||||
this.userMessageQueue = new RequestQueue(_msg);
|
||||
|
||||
// per-channel bot:msg:dm 10/10s
|
||||
const _bot_msg_dm =
|
||||
this._createBucketFactory(10, 10000, "bot:msg:dm", _bot_global);
|
||||
this.botDirectMessageQueues = new RequestQueueGroup(_bot_msg_dm);
|
||||
|
||||
// per-guild bot:msg:server 10/10s
|
||||
const _bot_msg_server =
|
||||
this._createBucketFactory(10, 10000, "bot:msg:server", _bot_global);
|
||||
this.botMessageQueues = new RequestQueueGroup(_bot_msg_server);
|
||||
|
||||
// per-guild dmsg 5/1s
|
||||
const _dmsg =
|
||||
this._createBucketFactory(5, 1000, "dmsg", _bot_global);
|
||||
this.messageDeleteQueues = new RequestQueueGroup(_dmsg);
|
||||
|
||||
// per-guild bdmsg 1/1s
|
||||
const _bdmsg =
|
||||
this._createBucketFactory(1, 1000, "bdmsg", _bot_global);
|
||||
this.messageBulkDeleteQueues = new RequestQueueGroup(_bdmsg);
|
||||
|
||||
// per-guild guild_member 10/10s
|
||||
const _guild_member =
|
||||
this._createBucketFactory(10, 10000, "guild_member", _bot_global);
|
||||
this.guildMemberPatchQueues = new RequestQueueGroup(_guild_member);
|
||||
|
||||
// per-guild guild_member_nick 1/1s
|
||||
const _guild_member_nick =
|
||||
this._createBucketFactory(1, 1000, "guild_member_nick", _bot_global);
|
||||
this.guildMemberNickQueues = new RequestQueueGroup(_guild_member_nick);
|
||||
|
||||
// all other requests go here with route as key
|
||||
// bucket size should be set by HTTP headers
|
||||
const _bot_generic =
|
||||
this._createBucketFactory(Infinity, 5000, "bot:generic", _bot_global);
|
||||
this.genericRequestQueues = new RequestQueueGroup(_bot_generic);
|
||||
|
||||
discordie.Dispatcher.on("GATEWAY_DISPATCH", e => {
|
||||
if (!e.data) return;
|
||||
|
||||
if (e.type === "READY") {
|
||||
if (!e.data.user) return;
|
||||
this.isBot = e.data.user.bot || false;
|
||||
}
|
||||
if (e.type === "GUILD_DELETE") {
|
||||
this._deleteGuildQueues(e.data.id);
|
||||
}
|
||||
if (e.type === "CHANNEL_DELETE") {
|
||||
this._deleteChannelQueues(e.data.id);
|
||||
}
|
||||
});
|
||||
|
||||
Utils.privatify(this);
|
||||
}
|
||||
|
||||
_reset() {
|
||||
Object.keys(this.buckets).forEach(k => this.buckets[k].refill());
|
||||
}
|
||||
|
||||
_createBucket(size, duration, name, parent) {
|
||||
if (!this.buckets[name]) {
|
||||
this.buckets[name] = new ChainedBucket(size, duration, name, parent);
|
||||
} else {
|
||||
this.buckets[name].refill();
|
||||
}
|
||||
return this.buckets[name];
|
||||
}
|
||||
|
||||
_createBucketFactory(size, duration, name, parent) {
|
||||
if (!this.bucketFactories[name]) {
|
||||
this.bucketFactories[name] =
|
||||
new BucketFactory(this, size, duration, name, parent);
|
||||
}
|
||||
return this.bucketFactories[name];
|
||||
}
|
||||
|
||||
put(request, sendCallback) {
|
||||
const route = request.path
|
||||
.replace(/\/\d+$/g, "")
|
||||
.replace(/\d+/g, ":id");
|
||||
|
||||
// convert to route: <- /api/guilds/:guild_id/bans/:user_id
|
||||
// -> /api/guilds/:id/bans
|
||||
// <- /api/channels/:channel_id
|
||||
// -> /api/channels/
|
||||
|
||||
const queue = this.genericRequestQueues.get(route);
|
||||
this._enqueueTo(queue, request, sendCallback);
|
||||
}
|
||||
|
||||
putToRoute(request, route, sendCallback) {
|
||||
const queue = this.genericRequestQueues.get(route);
|
||||
this._enqueueTo(queue, request, sendCallback);
|
||||
}
|
||||
|
||||
putMessage(request, channelId, sendCallback) {
|
||||
const channel = this._discordie._channels.get(channelId);
|
||||
|
||||
var queue = this.userMessageQueue;
|
||||
|
||||
if (this.isBot && channel) {
|
||||
if (channel.is_private || !channel.guild_id) {
|
||||
queue = this.botDirectMessageQueues.get(channelId);
|
||||
} else {
|
||||
queue = this.botMessageQueues.get(channel.guild_id);
|
||||
}
|
||||
}
|
||||
|
||||
this._enqueueTo(queue, request, sendCallback);
|
||||
}
|
||||
|
||||
putDeleteMessage(request, channelId, sendCallback) {
|
||||
const group = this.messageDeleteQueues;
|
||||
this._enqueueToGroup(group, request, channelId, sendCallback);
|
||||
}
|
||||
putBulkDeleteMessage(request, channelId, sendCallback) {
|
||||
const group = this.messageBulkDeleteQueues;
|
||||
this._enqueueToGroup(group, request, channelId, sendCallback);
|
||||
}
|
||||
|
||||
putGuildMemberPatch(request, guildId, sendCallback) {
|
||||
const queue = this.guildMemberPatchQueues.get(guildId);
|
||||
this._enqueueTo(queue, request, sendCallback);
|
||||
}
|
||||
putGuildMemberNick(request, guildId, sendCallback) {
|
||||
const queue = this.guildMemberNickQueues.get(guildId);
|
||||
this._enqueueTo(queue, request, sendCallback);
|
||||
}
|
||||
|
||||
_enqueueToGroup(group, request, channelId, sendCallback) {
|
||||
const channel = this._discordie._channels.get(channelId);
|
||||
const guildId = (channel && channel.guild_id) || null;
|
||||
|
||||
this._enqueueTo(group.get(guildId), request, sendCallback);
|
||||
}
|
||||
_enqueueTo(queue, request, sendCallback) {
|
||||
if (this.disabled) {
|
||||
return request.send(sendCallback);
|
||||
}
|
||||
queue.enqueue(request, sendCallback);
|
||||
}
|
||||
_deleteGuildQueues(guildId) {
|
||||
const groups = [
|
||||
this.botMessageQueues,
|
||||
this.messageDeleteQueues,
|
||||
this.messageBulkDeleteQueues,
|
||||
this.guildMemberPatchQueues
|
||||
];
|
||||
groups.forEach(g => g.delete(guildId));
|
||||
|
||||
this.genericRequestQueues.deleteContaining(guildId);
|
||||
}
|
||||
_deleteChannelQueues(channelId) {
|
||||
this.botDirectMessageQueues.delete(channelId);
|
||||
|
||||
this.genericRequestQueues.deleteContaining(channelId);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RequestQueueManager;
|
414
node_modules/discordie/lib/index.js
generated
vendored
Normal file
414
node_modules/discordie/lib/index.js
generated
vendored
Normal file
@ -0,0 +1,414 @@
|
||||
"use strict";
|
||||
|
||||
const DiscordieDispatcher = require("./core/DiscordieDispatcher");
|
||||
|
||||
const events = require("events");
|
||||
const request = require("./core/ApiRequest");
|
||||
const DiscordieError = require("./core/DiscordieError");
|
||||
const Constants = require("./Constants");
|
||||
const Events = Constants.Events;
|
||||
const GatewaySocket = require("./networking/ws/GatewaySocket");
|
||||
const Utils = require("./core/Utils");
|
||||
|
||||
const GuildCollection = require("./collections/GuildCollection");
|
||||
const ChannelCollection = require("./collections/ChannelCollection");
|
||||
const UserCollection = require("./collections/UserCollection");
|
||||
const GuildMemberCollection = require("./collections/GuildMemberCollection");
|
||||
const MessageCollection = require("./collections/MessageCollection");
|
||||
const PresenceCollection = require("./collections/PresenceCollection");
|
||||
const VoiceStateCollection = require("./collections/VoiceStateCollection");
|
||||
const VoiceConnectionCollection = require("./collections/VoiceConnectionCollection");
|
||||
const UnavailableGuildCollection = require("./collections/UnavailableGuildCollection");
|
||||
const GuildSyncCollection = require("./collections/GuildSyncCollection");
|
||||
const CallCollection = require("./collections/CallCollection");
|
||||
const User = require("./models/User");
|
||||
const AuthenticatedUser = require("./models/AuthenticatedUser");
|
||||
|
||||
const IGuildCollection = require("./interfaces/IGuildCollection");
|
||||
const IChannelCollection = require("./interfaces/IChannelCollection");
|
||||
const IAuthenticatedUser = require("./interfaces/IAuthenticatedUser");
|
||||
const IUserCollection = require("./interfaces/IUserCollection");
|
||||
const IMessageCollection = require("./interfaces/IMessageCollection");
|
||||
const IDirectMessageChannelCollection = require("./interfaces/IDirectMessageChannelCollection");
|
||||
const IInviteManager = require("./interfaces/IInviteManager");
|
||||
const IWebhookManager = require("./interfaces/IWebhookManager");
|
||||
|
||||
const RequestQueueManager = require("./core/ratelimiting/RequestQueueManager");
|
||||
const GatewayReconnectHandler = require("./core/GatewayReconnectHandler");
|
||||
const ReadyEventScheduler = require("./core/ReadyEventScheduler");
|
||||
|
||||
|
||||
const MessageHandlerCache = require("./core/MessageHandlerCache");
|
||||
const messageHandlerCache = new WeakMap();
|
||||
|
||||
const rest = require("./networking/rest");
|
||||
|
||||
function handleAuthLoginError(e) {
|
||||
this.pendingLogin = false;
|
||||
|
||||
this.Dispatcher.emit(
|
||||
Events.DISCONNECTED,
|
||||
{error: new DiscordieError("Login failed", e.error)}
|
||||
);
|
||||
}
|
||||
function handleAuthLoginSuccess(e) {
|
||||
this.pendingLogin = false;
|
||||
this.token = e.token;
|
||||
delete e.token;
|
||||
delete e.password;
|
||||
|
||||
rest(this).gateway();
|
||||
}
|
||||
|
||||
function handleGatewayError(e) {
|
||||
this.pendingLogin = false;
|
||||
|
||||
var ev = {error: new DiscordieError("Could not get gateway", e.error)};
|
||||
if (this.autoReconnect) this.autoReconnect._disconnected(ev);
|
||||
this.Dispatcher.emit(Events.DISCONNECTED, ev);
|
||||
}
|
||||
function handleGatewaySuccess(e) {
|
||||
this.pendingLogin = false;
|
||||
|
||||
this.gatewayEndpoint = e.gateway;
|
||||
this._createPrimaryGateway();
|
||||
}
|
||||
|
||||
function registerGatewayHandlers() {
|
||||
this.Dispatcher.on(Events.GATEWAY_DISPATCH, e => {
|
||||
if (e.suppress) { delete e.suppress; delete e.handled; return; }
|
||||
|
||||
const handlers = messageHandlerCache.get(this);
|
||||
if (!handlers.processGatewayMessage(e.socket, e.type, e.data) && !e.handled) {
|
||||
if (!e.socket.isPrimary) return;
|
||||
return this.Dispatcher.emit(
|
||||
Events.GATEWAY_UNHANDLED_MESSAGE,
|
||||
{type: e.type, data: e.data}
|
||||
);
|
||||
}
|
||||
|
||||
if (e.handled) delete e.handled;
|
||||
});
|
||||
|
||||
const onVoiceMessage = (type, e) => {
|
||||
if (e.suppress) { delete e.suppress; delete e.handled; return; }
|
||||
|
||||
const handlers = messageHandlerCache.get(this);
|
||||
if (!handlers.processVoiceMessage(e.socket, type, e.data) && !e.handled) {
|
||||
return this.Dispatcher.emit(
|
||||
Events.VOICESOCKET_UNHANDLED_MESSAGE,
|
||||
{type: type, data: e.data}
|
||||
);
|
||||
}
|
||||
|
||||
if (e.handled) delete e.handled;
|
||||
};
|
||||
|
||||
this.Dispatcher.on(Events.VOICE_READY, e => {
|
||||
onVoiceMessage("READY", e);
|
||||
});
|
||||
this.Dispatcher.on(Events.VOICE_SESSION_DESCRIPTION, e => {
|
||||
onVoiceMessage("SESSION_DESCRIPTION", e);
|
||||
});
|
||||
this.Dispatcher.on(Events.VOICE_SPEAKING, e => {
|
||||
onVoiceMessage("SPEAKING", e);
|
||||
});
|
||||
}
|
||||
|
||||
const defaultOptions = {
|
||||
compressMessages: true,
|
||||
messageQueue: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* @class
|
||||
* @classdesc
|
||||
* Additional constructor options:
|
||||
*
|
||||
* ```js
|
||||
* var client = new Discordie({
|
||||
* // Maximum amount of messages to store in channel cache.
|
||||
* // Decreasing this will reduce memory usage over time.
|
||||
* // With low values (below 50) chances of message invalidation increase:
|
||||
* // accessing message properties (ex. `e.message.channel`) in callbacks
|
||||
* // of long running tasks (ex. HTTP requests) becomes unsafe.
|
||||
* messageCacheLimit: 1000, // < default
|
||||
*
|
||||
* // Guild sharding:
|
||||
* // (Note that this is only intended to be used by large bots.)
|
||||
* // 'shardId' is a number starting at 0 and less than 'shardCount'
|
||||
* // 'shardCount' must be a number greater than 1
|
||||
* shardId: 0, shardCount: 2, // sharding is disabled by default
|
||||
*
|
||||
* // Gateway auto-reconnect:
|
||||
* // If enabled, 'DISCONNECTED' event will also contain properties
|
||||
* // 'autoReconnect' boolean, set to true
|
||||
* // 'delay' delay in milliseconds until next connect attempt
|
||||
* autoReconnect: false, // < default
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
class Discordie {
|
||||
constructor(options) {
|
||||
messageHandlerCache.set(this, new MessageHandlerCache(this));
|
||||
|
||||
if (!options) options = defaultOptions;
|
||||
const _defaultOptions = Object.assign({}, defaultOptions);
|
||||
this.options = Object.assign(_defaultOptions, options);
|
||||
Object.defineProperty(this, "options", {writable: false});
|
||||
|
||||
this.token = null;
|
||||
this.bot = false;
|
||||
|
||||
/**
|
||||
* Primary event bus.
|
||||
* @returns {EventEmitter}
|
||||
* @example
|
||||
* client.Dispatcher.on("GATEWAY_READY", e => {
|
||||
* console.log("Connected as: " + client.User.username);
|
||||
* });
|
||||
*/
|
||||
this.Dispatcher = new DiscordieDispatcher();
|
||||
|
||||
this.gatewaySocket = null;
|
||||
|
||||
const gw = () => this.gatewaySocket;
|
||||
|
||||
this._readyScheduler = new ReadyEventScheduler(this, gw);
|
||||
|
||||
this._user = new AuthenticatedUser();
|
||||
this._guilds = new GuildCollection(this, gw);
|
||||
this._channels = new ChannelCollection(this, gw);
|
||||
this._users = new UserCollection(this, gw);
|
||||
this._members = new GuildMemberCollection(this, gw);
|
||||
this._presences = new PresenceCollection(this, gw);
|
||||
this._messages = new MessageCollection(this, gw);
|
||||
this._voicestates = new VoiceStateCollection(this, gw);
|
||||
this._calls = new CallCollection(this, gw);
|
||||
|
||||
if (options.messageCacheLimit) {
|
||||
this._messages.setMessageLimit(options.messageCacheLimit);
|
||||
}
|
||||
|
||||
this._queueManager = new RequestQueueManager(this);
|
||||
if (!this.options.messageQueue) {
|
||||
this._queueManager.disabled = true;
|
||||
}
|
||||
|
||||
// == PUBLIC == //
|
||||
|
||||
/**
|
||||
* Represents current user.
|
||||
* @returns {IAuthenticatedUser}
|
||||
*/
|
||||
this.User = new IAuthenticatedUser(this);
|
||||
|
||||
/**
|
||||
* Interface to a collection containing all "Discord Servers"
|
||||
* (internally called guilds) current session is connected
|
||||
* to. Does not contain unavailable guilds.
|
||||
* @returns {IGuildCollection}
|
||||
*/
|
||||
this.Guilds = new IGuildCollection(this,
|
||||
() => this._guilds.values(),
|
||||
(key) => this._guilds.get(key));
|
||||
|
||||
/**
|
||||
* Interface to a collection containing all public channels current session
|
||||
* is connected to.
|
||||
* @returns {IChannelCollection}
|
||||
*/
|
||||
this.Channels = new IChannelCollection(this,
|
||||
() => this._channels.getGuildChannelIterator(),
|
||||
(key) => this._channels.getGuildChannel(key));
|
||||
|
||||
/**
|
||||
* Interface to a collection containing all users current session has
|
||||
* been exposed to.
|
||||
*
|
||||
* Contains only online users after `READY`.
|
||||
* See documentation for `IUserCollection.fetchMembers(guilds)` if you
|
||||
* want to load offline members too.
|
||||
* @returns {IUserCollection}
|
||||
*/
|
||||
this.Users = new IUserCollection(this,
|
||||
() => this._users.values(),
|
||||
(key) => this._users.get(key));
|
||||
|
||||
/**
|
||||
* Interface to a collection containing all private (direct message)
|
||||
* channels current session is connected to.
|
||||
* @returns {IDirectMessageChannelCollection}
|
||||
*/
|
||||
this.DirectMessageChannels = new IDirectMessageChannelCollection(this,
|
||||
() => this._channels.getPrivateChannelIterator(),
|
||||
(key) => this._channels.getPrivateChannel(key));
|
||||
|
||||
/**
|
||||
* Interface to a collection containing all cached messages.
|
||||
* @returns {IMessageCollection}
|
||||
*/
|
||||
this.Messages = new IMessageCollection(this,
|
||||
() => this._messages.getIterator(),
|
||||
(key) => this._messages.get(key));
|
||||
|
||||
/**
|
||||
* An instance of IInviteManager.
|
||||
* @returns {IInviteManager}
|
||||
*/
|
||||
this.Invites = new IInviteManager(this);
|
||||
|
||||
/**
|
||||
* An instance of IWebhookManager.
|
||||
* @returns {IWebhookManager}
|
||||
*/
|
||||
this.Webhooks = new IWebhookManager(this);
|
||||
|
||||
/**
|
||||
* An array of VoiceConnectionInfo.
|
||||
* @returns {Array<VoiceConnectionInfo>}
|
||||
*/
|
||||
this.VoiceConnections = VoiceConnectionCollection.create(this, gw);
|
||||
|
||||
/**
|
||||
* An array of unavailable guild's ids.
|
||||
* @returns {Array<String>}
|
||||
*/
|
||||
this.UnavailableGuilds = UnavailableGuildCollection.create(this, gw);
|
||||
|
||||
this.SyncedGuilds = new GuildSyncCollection(this, gw);
|
||||
|
||||
this._readyScheduler._waitFor(this.UnavailableGuilds);
|
||||
this._readyScheduler._addTask("GuildSync", this.SyncedGuilds);
|
||||
|
||||
// == EVENTS == //
|
||||
|
||||
this.Dispatcher.on(Events.REQUEST_AUTH_LOGIN_ERROR, handleAuthLoginError.bind(this));
|
||||
this.Dispatcher.on(Events.REQUEST_AUTH_LOGIN_SUCCESS, handleAuthLoginSuccess.bind(this));
|
||||
|
||||
this.Dispatcher.on(Events.REQUEST_GATEWAY_ERROR, handleGatewayError.bind(this));
|
||||
this.Dispatcher.on(Events.REQUEST_GATEWAY_SUCCESS, handleGatewaySuccess.bind(this));
|
||||
|
||||
/**
|
||||
* Auto-reconnect handler.
|
||||
* @returns {GatewayReconnectHandler}
|
||||
*/
|
||||
this.autoReconnect = new GatewayReconnectHandler(this);
|
||||
if (options.autoReconnect) this.autoReconnect.enable();
|
||||
|
||||
// must register our gateway/voice events last to check e.handled
|
||||
|
||||
registerGatewayHandlers.call(this);
|
||||
|
||||
Utils.privatify(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current state.
|
||||
*
|
||||
* Possible return values:
|
||||
*
|
||||
* - **`DISCONNECTED`**: Initial state. Returned if token is not available.
|
||||
* - **`LOGGING_IN`**
|
||||
* - **`LOGGED_IN`**: Returned if token is set, but gateway websocket is
|
||||
* not connected.
|
||||
* - **`CONNECTING`**
|
||||
* - **`CONNECTED`**
|
||||
*
|
||||
* State `CONNECTED` only indicates state of gateway websocket connection,
|
||||
* returns both before and after `READY`.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
*/
|
||||
get state() {
|
||||
if (this.pendingLogin)
|
||||
return Constants.DiscordieState.LOGGING_IN;
|
||||
|
||||
if (this.gatewaySocket) {
|
||||
if (this.gatewaySocket.connected)
|
||||
return Constants.DiscordieState.CONNECTED;
|
||||
if (this.gatewaySocket.connecting)
|
||||
return Constants.DiscordieState.CONNECTING;
|
||||
}
|
||||
|
||||
if (this.token)
|
||||
return Constants.DiscordieState.LOGGED_IN;
|
||||
|
||||
return Constants.DiscordieState.DISCONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the gateway websocket connection is
|
||||
* established.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get connected() {
|
||||
return this.state == Constants.DiscordieState.CONNECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} credentials - Can contain `email`, `password` or `token`
|
||||
*/
|
||||
connect(credentials) {
|
||||
if (this.state == Constants.DiscordieState.CONNECTED
|
||||
|| this.state == Constants.DiscordieState.CONNECTING
|
||||
|| this.pendingLogin)
|
||||
return;
|
||||
|
||||
this.pendingLogin = true;
|
||||
|
||||
if (credentials && credentials.hasOwnProperty("bot")) {
|
||||
this.bot = credentials.bot;
|
||||
}
|
||||
|
||||
if (credentials && credentials.token) {
|
||||
this.token = credentials.token;
|
||||
credentials = null;
|
||||
}
|
||||
|
||||
if (!credentials && this.token) {
|
||||
rest(this).gateway();
|
||||
return;
|
||||
}
|
||||
|
||||
rest(this).auth.login(credentials);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects primary gateway websocket.
|
||||
*/
|
||||
disconnect() {
|
||||
if (this.gatewaySocket) {
|
||||
this.gatewaySocket.disconnect();
|
||||
this.gatewaySocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
_createPrimaryGateway() {
|
||||
if (!this.gatewaySocket) {
|
||||
const compressMessages = this.options.compressMessages;
|
||||
const shardId = this.options.shardId;
|
||||
const shardCount = this.options.shardCount;
|
||||
|
||||
const gatewayOptions = {compressMessages, shardId, shardCount};
|
||||
|
||||
this.gatewaySocket = new GatewaySocket(this, gatewayOptions);
|
||||
}
|
||||
this.gatewaySocket.connect(this.gatewayEndpoint);
|
||||
}
|
||||
}
|
||||
|
||||
Discordie.Events = Constants.Events;
|
||||
Discordie.StatusTypes = Constants.StatusTypes;
|
||||
Discordie.ActivityTypes = Constants.ActivityTypes;
|
||||
Discordie.States = Constants.DiscordieState;
|
||||
Discordie.Permissions = Constants.Permissions;
|
||||
Discordie.VerificationLevel = Constants.VerificationLevel;
|
||||
Discordie.MFALevels = Constants.MFALevels;
|
||||
Discordie.UserNotificationSettings = Constants.UserNotificationSettings;
|
||||
Discordie.Errors = Constants.Errors;
|
||||
Discordie.ChannelTypes = Constants.ChannelTypes;
|
||||
Discordie.MessageTypes = Constants.MessageTypes;
|
||||
|
||||
module.exports = Discordie;
|
327
node_modules/discordie/lib/interfaces/IAuthenticatedUser.js
generated
vendored
Normal file
327
node_modules/discordie/lib/interfaces/IAuthenticatedUser.js
generated
vendored
Normal file
@ -0,0 +1,327 @@
|
||||
"use strict";
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const IUser = require("./IUser");
|
||||
const Utils = require("../core/Utils");
|
||||
const AuthenticatedUser = require("../models/AuthenticatedUser");
|
||||
const Constants = require("../Constants");
|
||||
const StatusTypes = Constants.StatusTypes;
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model AuthenticatedUser
|
||||
* @extends IBase
|
||||
*/
|
||||
class IAuthenticatedUser extends IBase {
|
||||
constructor(discordie) {
|
||||
super();
|
||||
Utils.definePrivate(this, {_discordie: discordie});
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets date and time the account was registered (created) at.
|
||||
* @returns {Date}
|
||||
* @readonly
|
||||
*/
|
||||
get registeredAt() {
|
||||
return new Date(Utils.timestampFromSnowflake(this.id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets current JPG or GIF avatar URL.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get avatarURL() {
|
||||
return Object.getOwnPropertyDescriptor(IUser.prototype, "avatarURL")
|
||||
.get.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets current JPG avatar URL.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get staticAvatarURL() {
|
||||
return Object.getOwnPropertyDescriptor(IUser.prototype, "staticAvatarURL")
|
||||
.get.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether the account is claimed.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isClaimedAccount() {
|
||||
return this.email != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the user is mentioned in a `message`.
|
||||
* @param {IMessage} message
|
||||
* @param {boolean} ignoreImplicitMentions
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isMentioned(message, ignoreImplicitMentions) {
|
||||
return IUser.prototype.isMentioned.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to get the bot's OAuth2 application info.
|
||||
*
|
||||
* Works only with bot accounts.
|
||||
*
|
||||
* Example response object:
|
||||
* ```js
|
||||
* {
|
||||
* "description": "Test",
|
||||
* "icon": null,
|
||||
* "id": "179527948411052118",
|
||||
* "name": "app name or something",
|
||||
* "rpc_origins": [],
|
||||
* "flags": 0,
|
||||
* "owner": {
|
||||
* "username": "bot owner",
|
||||
* "discriminator": "4937",
|
||||
* "id": "169454786183781631",
|
||||
* "avatar": null
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
getApplication() {
|
||||
return rest(this._discordie).oauth2.getApplication(Constants.ME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to edit user profile,
|
||||
* substituting `undefined` or `null` properties with current values.
|
||||
*
|
||||
* Passing `null` in `avatar` will remove current avatar. Use `undefined`
|
||||
* instead of `null` in this case.
|
||||
* @param {String} currentPassword - Use null as password on bot accounts
|
||||
* @param {String} [username]
|
||||
* @param {String|Buffer|null} [avatar] - Buffer or base64 data URL
|
||||
* @param {String} [email]
|
||||
* @param {String} [newPassword]
|
||||
* @returns {Promise<IUser, Error>}
|
||||
* @example
|
||||
* // avatar from file
|
||||
* client.User.edit(currentPassword, null, fs.readFileSync("test.png"));
|
||||
* client.User.edit(currentPassword, null, fs.readFileSync("test.jpg"));
|
||||
* // avatar unchanged
|
||||
* client.User.edit(currentPassword, "test", undefined, "new@example.com");
|
||||
* client.User.edit(currentPassword, "test", client.User.avatar);
|
||||
* // no avatar / default avatar
|
||||
* client.User.edit(currentPassword, "test", null);
|
||||
*/
|
||||
edit(currentPassword, username, avatar, email, newPassword) {
|
||||
const user = this._discordie._user;
|
||||
username = username || user.username;
|
||||
email = email || user.email;
|
||||
newPassword = newPassword || null;
|
||||
|
||||
if (avatar instanceof Buffer) {
|
||||
avatar = Utils.imageToDataURL(avatar);
|
||||
} else if (avatar === undefined) {
|
||||
avatar = user.avatar;
|
||||
}
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.users.me(currentPassword, username, avatar, email, newPassword)
|
||||
.then(() => rs(this._discordie.User))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to edit avatar.
|
||||
*
|
||||
* Setting avatar to `null` will remove current avatar.
|
||||
* @param {String|Buffer|null} avatar - Buffer or base64 data URL
|
||||
* @param {String} [currentPassword] - Not applicable for bot accounts
|
||||
* @returns {Promise<IUser, Error>}
|
||||
* @example
|
||||
* // avatar from file
|
||||
* client.User.setAvatar(fs.readFileSync("test.png"));
|
||||
* // remove avatar
|
||||
* client.User.setAvatar(null);
|
||||
*/
|
||||
setAvatar(avatar, currentPassword) {
|
||||
return this.edit(currentPassword, null, avatar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to edit username.
|
||||
* @param {String} username
|
||||
* @param {String} [currentPassword] - Not applicable for bot accounts
|
||||
* @returns {Promise<IUser, Error>}
|
||||
*/
|
||||
setUsername(username, currentPassword) {
|
||||
return this.edit(currentPassword, username);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets current user status via websocket.
|
||||
*
|
||||
* With multiple sessions status from last connected will override statuses
|
||||
* from previous sessions.
|
||||
*
|
||||
* > Note: By default Discord client does not display game/status updates for
|
||||
* > the user it's logged in into. It will be visible for other users.
|
||||
* @param {Object|String} status
|
||||
* Object `{status: String, afk: boolean}` or string.
|
||||
* Field `afk` changes how Discord handles push notifications.
|
||||
* @param {Object|String|null} [game] - Object `{name: String}` or string
|
||||
* @example
|
||||
* var game = {name: "with code"}; // sets status as "Playing with code"
|
||||
* var streamingGame = {type: 1, name: "something", url: ""}; // "Streaming"
|
||||
* // note: streaming status requires a valid twitch url:
|
||||
* // ex. "http://twitch.tv/channel"
|
||||
* client.User.setStatus("idle", game); // idle, playing
|
||||
* client.User.setStatus(null, game); // no status change, playing
|
||||
* client.User.setStatus(null, "with code"); // no status change, playing
|
||||
* client.User.setStatus(null, streamingGame); // no status change, streaming
|
||||
* client.User.setStatus("online", game); // online, playing
|
||||
* client.User.setStatus("idle", null); // idle, not playing
|
||||
* client.User.setStatus("dnd"); // "do not disturb"
|
||||
* client.User.setStatus("invisible");
|
||||
* client.User.setStatus({status: "idle", afk: true});
|
||||
*/
|
||||
setStatus(status, game) {
|
||||
if (arguments.length == 0) return;
|
||||
|
||||
var afk = this.afk;
|
||||
if (!status) status = this.status;
|
||||
if (typeof status === "object") {
|
||||
afk = status.afk != null ? !!status.afk : this.afk;
|
||||
status = status.status != null ? status.status : this.status;
|
||||
}
|
||||
|
||||
if (game === undefined) game = this.game;
|
||||
if (typeof game === "string") game = {name: game};
|
||||
|
||||
status = Object.keys(StatusTypes).map(v => StatusTypes[v])
|
||||
.find(v => v === status.toLowerCase());
|
||||
status = status || StatusTypes.ONLINE;
|
||||
|
||||
if (this._discordie._user) {
|
||||
this._discordie._user = this._discordie._user.merge({status, game, afk});
|
||||
}
|
||||
|
||||
if (!this._discordie.gatewaySocket) return;
|
||||
|
||||
this._discordie.gatewaySocket.statusUpdate(
|
||||
status,
|
||||
status === StatusTypes.IDLE ? Date.now() : null,
|
||||
game,
|
||||
afk
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets playing game for current user via websocket.
|
||||
*
|
||||
* With multiple sessions status from last connected will override statuses
|
||||
* from previous sessions.
|
||||
*
|
||||
* > Note: By default Discord client does not display game/status updates for
|
||||
* > the user it's logged in into. It will be visible for other users.
|
||||
* @param {Object|String|null} game - Object `{name: String}` or string
|
||||
* @example
|
||||
* var game = {name: "with code"}; // sets game as "Playing with code"
|
||||
* var streamingGame = {type: 1, name: "something", url: ""}; // "Streaming"
|
||||
* // note: streaming status requires a valid twitch url:
|
||||
* // ex. "http://twitch.tv/channel"
|
||||
* client.User.setGame(game); // playing
|
||||
* client.User.setGame("with code"); // playing
|
||||
* client.User.setGame(streamingGame); // streaming
|
||||
* client.User.setGame(null); // not playing
|
||||
*/
|
||||
setGame(game) {
|
||||
if (arguments.length == 0) return;
|
||||
this.setStatus(null, game);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the game current user is playing.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get gameName() {
|
||||
return this.game ? this.game.name : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempts to get a guild member interface, returns null if this user is not
|
||||
* a member of the `guild` or `guild` is not in cache.
|
||||
* @param {IGuild|String} guild
|
||||
* @returns {IGuildMember|null}
|
||||
*/
|
||||
memberOf(guild) {
|
||||
return this._discordie.Users.getMember(guild.valueOf(), this.id) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* See `IUser.permissionsFor`.
|
||||
* @see IUser.permissionsFor
|
||||
* @param {IChannel|IGuild} context
|
||||
* @returns {IPermissions}
|
||||
*/
|
||||
permissionsFor(context) {
|
||||
return IUser.prototype.permissionsFor.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* See `IUser.can`.
|
||||
* @see IUser.can
|
||||
* @param {Number} permission - One or multiple permission bits
|
||||
* @param {IChannel|IGuild} context
|
||||
* @returns {boolean}
|
||||
*/
|
||||
can(permission, context) {
|
||||
return IUser.prototype.can.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* See `IUser.getVoiceChannel`.
|
||||
* @see IUser.getVoiceChannel
|
||||
* @param {IGuild|String} guild - Guild or an id string
|
||||
* @returns {IVoiceChannel|null}
|
||||
*/
|
||||
getVoiceChannel(guild) {
|
||||
return IUser.prototype.getVoiceChannel.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mention from this user's id.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
* @example
|
||||
* channel.sendMessage(user.mention + ", example mention");
|
||||
*/
|
||||
get mention() {
|
||||
return `<@${this.id}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nickname mention from this user's id.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
*/
|
||||
get nickMention() {
|
||||
return `<@!${this.id}>`;
|
||||
}
|
||||
}
|
||||
|
||||
IAuthenticatedUser._inherit(AuthenticatedUser, function(key) {
|
||||
return this._discordie._user[key];
|
||||
});
|
||||
|
||||
module.exports = IAuthenticatedUser;
|
157
node_modules/discordie/lib/interfaces/IBase.js
generated
vendored
Normal file
157
node_modules/discordie/lib/interfaces/IBase.js
generated
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
"use strict";
|
||||
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
class IBase {
|
||||
static _inherit(proto, get) {
|
||||
var thisProto = this.prototype;
|
||||
thisProto._valueOverrides = thisProto._valueOverrides || {};
|
||||
thisProto._gettersByProperty = thisProto._gettersByProperty || {};
|
||||
thisProto._suppressErrors = false;
|
||||
Object.defineProperties(thisProto, {
|
||||
_valueOverrides: {enumerable: false},
|
||||
_gettersByProperty: {enumerable: false},
|
||||
_suppressErrors: {enumerable: false}
|
||||
});
|
||||
|
||||
thisProto._gettersByProperty[this.name] =
|
||||
thisProto._gettersByProperty[this.name] || {};
|
||||
|
||||
const interfacingProperties = new proto();
|
||||
for (let key in interfacingProperties) {
|
||||
thisProto._gettersByProperty[this.name][key] = get;
|
||||
|
||||
Object.defineProperty(thisProto, key, {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: function() {
|
||||
const __thisproto__ = Object.getPrototypeOf(this);
|
||||
try {
|
||||
const value = get.call(this, key);
|
||||
if (__thisproto__._valueOverrides[key]) {
|
||||
return __thisproto__._valueOverrides[key].call(this, value);
|
||||
}
|
||||
return value;
|
||||
} catch (e) {
|
||||
const __ctrproto__ = Object.getPrototypeOf(this.constructor);
|
||||
if (!__ctrproto__._suppressErrors) console.error(e.stack);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
static _setValueOverride(k, fn) {
|
||||
if (!this.prototype.hasOwnProperty(k)) {
|
||||
throw new Error(
|
||||
`Property '${k}' is not defined for ${this.constructor.name}`
|
||||
);
|
||||
}
|
||||
|
||||
if (typeof fn !== "function") {
|
||||
return delete this._valueOverrides[k];
|
||||
}
|
||||
this.prototype._valueOverrides[k] = fn;
|
||||
}
|
||||
static _setSuppressErrors(value) {
|
||||
Object.getPrototypeOf(this)._suppressErrors = value;
|
||||
}
|
||||
|
||||
// Get a copy of raw model data or property
|
||||
getRaw(property) {
|
||||
var allGetters = Object.getPrototypeOf(this)._gettersByProperty;
|
||||
var getters = allGetters[this.constructor.name];
|
||||
if (!getters) {
|
||||
// no own properties, lookup last inherited class
|
||||
var lastClass = Object.keys(allGetters).pop();
|
||||
getters = allGetters[lastClass];
|
||||
}
|
||||
|
||||
getters = getters || {};
|
||||
|
||||
if (property) {
|
||||
if (!getters.hasOwnProperty(property)) return;
|
||||
return getters[property].call(this, property);
|
||||
}
|
||||
|
||||
var copy = {};
|
||||
for (var key in this) {
|
||||
try {
|
||||
if (getters.hasOwnProperty(key))
|
||||
copy[key] = getters[key].call(this, key);
|
||||
} catch (e) {
|
||||
copy[key] = null;
|
||||
console.error("Could not get key", key);
|
||||
console.error(e.stack);
|
||||
}
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Get a copy of internal model data, including inherited properties
|
||||
toJSON() {
|
||||
var copy = {};
|
||||
const __thisproto__ = Object.getPrototypeOf(this);
|
||||
for (var classname in __thisproto__._gettersByProperty) {
|
||||
var getters = __thisproto__._gettersByProperty[classname];
|
||||
for (var key in this) {
|
||||
try {
|
||||
if (getters.hasOwnProperty(key)) {
|
||||
copy[key] = getters[key].call(this, key);
|
||||
const v = copy[key];
|
||||
const type = v && v.constructor && v.constructor.name;
|
||||
if (type === "Set") copy[key] = Array.from(v);
|
||||
if (type === "Map") copy[key] = Array.from(v.values());
|
||||
}
|
||||
} catch (e) {
|
||||
copy[key] = null;
|
||||
console.error("Could not get key ", key);
|
||||
console.error(e.stack);
|
||||
}
|
||||
}
|
||||
if (classname === this.constructor.name) break;
|
||||
}
|
||||
return copy;
|
||||
}
|
||||
|
||||
// Custom inspect output (console.log, util.format, util.inspect)
|
||||
inspect() {
|
||||
var copy = new (
|
||||
// create fake object to preserve class name
|
||||
new Function("return function " + this.constructor.name + "(){}")()
|
||||
);
|
||||
for (var key in this) { copy[key] = this[key]; }
|
||||
return copy;
|
||||
}
|
||||
|
||||
get _valid() {
|
||||
try {
|
||||
var allGetters = Object.getPrototypeOf(this)._gettersByProperty;
|
||||
for (var classname in allGetters) {
|
||||
if (allGetters[classname].hasOwnProperty("id"))
|
||||
return allGetters[classname]["id"].call(this, "id");
|
||||
}
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
valueOf() {
|
||||
if (!this.id) return null;
|
||||
return this.id;
|
||||
}
|
||||
equals(b) {
|
||||
return this.valueOf() === b.valueOf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets date and time this object was created at.
|
||||
* @returns {Date}
|
||||
* @readonly
|
||||
*/
|
||||
get createdAt() {
|
||||
return new Date(Utils.timestampFromSnowflake(this.id));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IBase;
|
75
node_modules/discordie/lib/interfaces/ICall.js
generated
vendored
Normal file
75
node_modules/discordie/lib/interfaces/ICall.js
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
const Call = require("../models/Call");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model Call
|
||||
* @extends IBase
|
||||
*/
|
||||
class ICall extends IBase {
|
||||
constructor(discordie, directMessageChannelId) {
|
||||
super();
|
||||
Utils.definePrivate(this, {
|
||||
_discordie: discordie,
|
||||
_directMessageChannelId: directMessageChannelId
|
||||
});
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets date and time this call was created at.
|
||||
* @returns {Date}
|
||||
* @readonly
|
||||
*/
|
||||
get createdAt() {
|
||||
const call = this._discordie._calls.get(this._directMessageChannelId);
|
||||
if (!call) return new Date(null);
|
||||
|
||||
return new Date(Utils.timestampFromSnowflake(call.message_id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the call is ringing for current user.
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isRinging() {
|
||||
const call = this._discordie._calls.get(this._directMessageChannelId);
|
||||
if (!call) return false;
|
||||
|
||||
const userId = this._discordie._user && this._discordie._user.id;
|
||||
if (!userId) return false;
|
||||
|
||||
return call.ringing ? call.ringing.indexOf(userId) >= 0 : false;
|
||||
}
|
||||
}
|
||||
|
||||
ICall._inherit(Call, function modelPropertyGetter(key) {
|
||||
return this._discordie._calls.get(this._directMessageChannelId)[key];
|
||||
});
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf ICall
|
||||
* @name ringing
|
||||
* @returns {Array<IUser>|null}
|
||||
*/
|
||||
ICall._setValueOverride("ringing", function(ringing) {
|
||||
const users = [];
|
||||
if (!ringing) return users;
|
||||
for (let id of ringing) {
|
||||
const user = this._discordie.Users.get(id);
|
||||
if (user) users.push(user);
|
||||
}
|
||||
return users;
|
||||
});
|
||||
|
||||
module.exports = ICall;
|
307
node_modules/discordie/lib/interfaces/IChannel.js
generated
vendored
Normal file
307
node_modules/discordie/lib/interfaces/IChannel.js
generated
vendored
Normal file
@ -0,0 +1,307 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const ChannelTypes = Constants.ChannelTypes;
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const Utils = require("../core/Utils");
|
||||
const Channel = require("../models/Channel");
|
||||
const IUser = require("./IUser");
|
||||
const IRole = require("./IRole");
|
||||
const IGuildMember = require("./IGuildMember");
|
||||
const IAuthenticatedUser = require("./IAuthenticatedUser");
|
||||
const IPermissions = require("./IPermissions");
|
||||
const IPermissionOverwrite = require("./IPermissionOverwrite");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model Channel
|
||||
* @extends IBase
|
||||
* @description
|
||||
* Base channel class.
|
||||
*
|
||||
* Use the `type` property to determine whether it is a
|
||||
* `ITextChannel`, `IDirectMessageChannel` or `IVoiceChannel`:
|
||||
*
|
||||
* ```js
|
||||
* Discordie.ChannelTypes: {
|
||||
* GUILD_TEXT: 0, // ITextChannel
|
||||
* DM: 1, // IDirectMessageChannel
|
||||
* GUILD_VOICE: 2, // IVoiceChannel
|
||||
* GROUP_DM: 3 // IDirectMessageChannel
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class IChannel extends IBase {
|
||||
constructor(discordie, channelId) {
|
||||
super();
|
||||
Utils.definePrivate(this, {
|
||||
_discordie: discordie,
|
||||
_channelId: channelId
|
||||
});
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* **Deprecated**: Removed in API v6. Use `isPrivate` instead.
|
||||
* @return {boolean|null}
|
||||
* @readonly
|
||||
*/
|
||||
get is_private() {
|
||||
return this.isPrivate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a direct message channel or a group.
|
||||
* @return {boolean|null}
|
||||
* @readonly
|
||||
*/
|
||||
get isPrivate() {
|
||||
if (!this._valid) return null;
|
||||
return this._discordie._channels._isPrivate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a voice channel in a guild.
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isGuildVoice() {
|
||||
return this.type === ChannelTypes.GUILD_VOICE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a text channel in a guild.
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isGuildText() {
|
||||
return this.type === ChannelTypes.GUILD_TEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a direct message channel (non-group).
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isDM() {
|
||||
return this.type === ChannelTypes.DM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a group direct message channel.
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isGroupDM() {
|
||||
return this.type === ChannelTypes.GROUP_DM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets guild of this channel.
|
||||
* @returns {IGuild|null}
|
||||
* @readonly
|
||||
*/
|
||||
get guild() {
|
||||
return this._discordie.Guilds.get(this.guild_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create an invite for this channel.
|
||||
* @param {Object} options
|
||||
* @returns {Promise<Object, Error>}
|
||||
* @example
|
||||
* channel.createInvite({
|
||||
* max_age: 60 * 60 * 24, // value in seconds
|
||||
* max_uses: 0, // pretty obvious
|
||||
* temporary: false
|
||||
* // temporary membership, kicks members without roles on disconnect
|
||||
* });
|
||||
* // Example response:
|
||||
* {
|
||||
* "max_age": 86400,
|
||||
* "code": "AAAAAAAAAAAAAAAA",
|
||||
* "guild": {
|
||||
* "splash_hash": null,
|
||||
* "id": "00000000000000000",
|
||||
* "name": "test"
|
||||
* },
|
||||
* "revoked": false,
|
||||
* "created_at": "2015-10-16T10:45:38.566978+00:00",
|
||||
* "temporary": false,
|
||||
* "uses": 0,
|
||||
* "max_uses": 0,
|
||||
* "inviter": {
|
||||
* "username": "testuser",
|
||||
* "discriminator": "3273",
|
||||
* "bot": true,
|
||||
* "id": "00000000000000000",
|
||||
* "avatar": null
|
||||
* },
|
||||
* "channel": {
|
||||
* "type": "text",
|
||||
* "id": "000000000000000000",
|
||||
* "name": "testchannel"
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
createInvite(options) {
|
||||
return this._discordie.Invites.create(this, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create a permission overwrite for this channel.
|
||||
* @param {IAuthenticatedUser|IRole|IGuildMember} roleOrMember
|
||||
* @param {IPermissions|Number} [allow]
|
||||
* @param {IPermissions|Number} [deny]
|
||||
* @returns {Promise<IPermissionOverwrite, Error>}
|
||||
* @example
|
||||
* channel.createPermissionOverwrite(this.User);
|
||||
* channel.createPermissionOverwrite(
|
||||
* channel.guild.members.find(m => m.username == "testuser")
|
||||
* );
|
||||
* channel.createPermissionOverwrite(
|
||||
* channel.guild.roles.find(r => r.name == "new role")
|
||||
* )
|
||||
* .then(overwrite => console.log(overwrite))
|
||||
* .catch(error => console.log(error));
|
||||
*/
|
||||
createPermissionOverwrite(roleOrMember, allow, deny) {
|
||||
if (![IAuthenticatedUser, IRole, IGuildMember]
|
||||
.some(t => roleOrMember instanceof t))
|
||||
throw new TypeError(
|
||||
"roleOrMember must be an instance of IRole or IGuildMember"
|
||||
);
|
||||
|
||||
if (allow === undefined) allow = 0;
|
||||
if (deny === undefined) deny = 0;
|
||||
if (allow instanceof IPermissions) allow = allow.raw;
|
||||
if (deny instanceof IPermissions) deny = deny.raw;
|
||||
const types = [
|
||||
{t: IRole, s: "role"},
|
||||
{t: IGuildMember, s: "member"},
|
||||
{t: IAuthenticatedUser, s: "member"}
|
||||
];
|
||||
const type = types.find(spec => roleOrMember instanceof spec.t).s;
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
const raw = {
|
||||
id: roleOrMember.valueOf(),
|
||||
type: type,
|
||||
allow: allow,
|
||||
deny: deny
|
||||
};
|
||||
rest(this._discordie)
|
||||
.channels.putPermissionOverwrite(this._channelId, raw)
|
||||
.then(o =>
|
||||
rs(new IPermissionOverwrite(this._discordie, o.id, this._channelId))
|
||||
)
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to update this channel.
|
||||
* @param {String} [name]
|
||||
* @param {String} [topic]
|
||||
* @param {Number} [bitrate] - Only for voice channels
|
||||
* @param {Number} [userLimit] - Only for voice channels
|
||||
* @returns {Promise<IChannel, Error>}
|
||||
*/
|
||||
update(name, topic, bitrate, userLimit) {
|
||||
if (typeof name !== "string") name = this.name;
|
||||
if (typeof topic !== "string") topic = this.topic;
|
||||
if (typeof bitrate !== "number") bitrate = this.bitrate;
|
||||
if (typeof userLimit !== "number") userLimit = this.user_limit;
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.channels.patchChannel(this.id,
|
||||
name, topic, bitrate, userLimit, this.position
|
||||
)
|
||||
.then((channel) => rs(this._discordie.Channels.get(channel.id)))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create a new channel with permission overwrites of
|
||||
* this channel.
|
||||
* @param {String} name
|
||||
* @param {Number} [type] - See IChannel / Discordie.ChannelTypes
|
||||
* @param {Number} [bitrate] - Only for voice channels
|
||||
* @param {Number} [userLimit] - Only for voice channels
|
||||
*/
|
||||
clone(name, type, bitrate, userLimit) {
|
||||
if (!this._valid) return Promise.reject(new Error("Invalid channel"));
|
||||
if (!this.guild) return Promise.reject(new Error("Invalid guild"));
|
||||
name = name != null ? name : this.name;
|
||||
type = type != null ? type : this.type;
|
||||
if (type === ChannelTypes.GUILD_VOICE || type === "voice") {
|
||||
if (bitrate == null) bitrate = this.bitrate;
|
||||
if (userLimit == null) userLimit = this.user_limit;
|
||||
}
|
||||
const permissionOverwrites = this.permission_overwrites;
|
||||
return this.guild
|
||||
.createChannel(type, name, permissionOverwrites, bitrate, userLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves this channel to `position` and makes a batch channel update request.
|
||||
* @param {Number} position
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setPosition(position) {
|
||||
const channels = (this.type == ChannelTypes.GUILD_VOICE) ?
|
||||
this.guild.voiceChannels :
|
||||
this.guild.textChannels;
|
||||
|
||||
const changes = Utils.reorderObjects(channels, this, position);
|
||||
if (!changes) return Promise.resolve();
|
||||
|
||||
return rest(this._discordie)
|
||||
.channels.batchPatchChannels(this.guild_id, changes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete this channel.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
delete() {
|
||||
return rest(this._discordie).channels.deleteChannel(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to get a list of invites for this channel.
|
||||
* @returns {Promise<Array<Object>, Error>}
|
||||
*/
|
||||
getInvites() {
|
||||
return rest(this._discordie).channels.getInvites(this.id);
|
||||
}
|
||||
}
|
||||
|
||||
IChannel._inherit(Channel, function modelPropertyGetter(key) {
|
||||
return this._discordie._channels.get(this._channelId)[key];
|
||||
});
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IChannel
|
||||
* @name permission_overwrites
|
||||
* @returns {Array<IPermissionOverwrite>}
|
||||
*/
|
||||
IChannel._setValueOverride("permission_overwrites", function(overwritesRaw) {
|
||||
const overwrites = [];
|
||||
if (!overwritesRaw) return overwrites;
|
||||
for (let overwrite of overwritesRaw) {
|
||||
overwrites.push(new IPermissionOverwrite(
|
||||
this._discordie, overwrite.id, this._channelId
|
||||
));
|
||||
}
|
||||
return overwrites;
|
||||
});
|
||||
|
||||
module.exports = IChannel;
|
65
node_modules/discordie/lib/interfaces/IChannelCollection.js
generated
vendored
Normal file
65
node_modules/discordie/lib/interfaces/IChannelCollection.js
generated
vendored
Normal file
@ -0,0 +1,65 @@
|
||||
"use strict";
|
||||
|
||||
const ICollectionBase = require("./ICollectionBase");
|
||||
const IChannel = require("./IChannel");
|
||||
const ITextChannel = require("./ITextChannel");
|
||||
const IVoiceChannel = require("./IVoiceChannel");
|
||||
const IGuild = require("./IGuild");
|
||||
const Utils = require("../core/Utils");
|
||||
const Constants = require("../Constants");
|
||||
const ChannelTypes = Constants.ChannelTypes;
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @extends ICollectionBase
|
||||
*/
|
||||
class IChannelCollection extends ICollectionBase {
|
||||
constructor(discordie, valuesGetter, valueGetter) {
|
||||
super({
|
||||
valuesGetter: valuesGetter,
|
||||
valueGetter: valueGetter,
|
||||
itemFactory: (id) => {
|
||||
const type = this._discordie._channels.getChannelType(id);
|
||||
if (type && type === ChannelTypes.GUILD_VOICE) {
|
||||
return new IVoiceChannel(this._discordie, id);
|
||||
}
|
||||
return new ITextChannel(this._discordie, id);
|
||||
}
|
||||
});
|
||||
Utils.definePrivate(this, {_discordie: discordie});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of `IChannel` (`ITextChannel` and `IVoiceChannel`)
|
||||
* for `guild`.
|
||||
* @param {IGuild|String} guild
|
||||
* @returns {Array<IChannel>}
|
||||
*/
|
||||
forGuild(guild) {
|
||||
return this.filter(channel => channel.guild_id == guild.valueOf());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of `ITextChannel` for `guild`.
|
||||
* @param {IGuild|String} guild
|
||||
* @returns {Array<ITextChannel>}
|
||||
*/
|
||||
textForGuild(guild) {
|
||||
return this.filter(channel =>
|
||||
channel.guild_id == guild && channel.type == ChannelTypes.GUILD_TEXT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of `IVoiceChannel` for `guild`.
|
||||
* @param {IGuild|String} guild
|
||||
* @returns {Array<IVoiceChannel>}
|
||||
*/
|
||||
voiceForGuild(guild) {
|
||||
return this.filter(channel =>
|
||||
channel.guild_id == guild && channel.type == ChannelTypes.GUILD_VOICE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IChannelCollection;
|
192
node_modules/discordie/lib/interfaces/ICollectionBase.js
generated
vendored
Normal file
192
node_modules/discordie/lib/interfaces/ICollectionBase.js
generated
vendored
Normal file
@ -0,0 +1,192 @@
|
||||
"use strict";
|
||||
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
class ICollectionBase {
|
||||
constructor(descriptor) {
|
||||
if (!descriptor.valuesGetter)
|
||||
throw new Error("valuesGetter is not defined");
|
||||
if (!descriptor.itemFactory)
|
||||
throw new Error("itemFactory is not defined");
|
||||
|
||||
this._valuesGetter = descriptor.valuesGetter;
|
||||
this._valueGetter = descriptor.valueGetter;
|
||||
this._itemFactory = descriptor.itemFactory;
|
||||
this._cache = new WeakMap();
|
||||
Utils.privatify(this);
|
||||
}
|
||||
_getOrCreateInterface(item, customItemFactory) {
|
||||
var factory = customItemFactory || this._itemFactory;
|
||||
var cache = this._cache;
|
||||
if (!cache.get(item))
|
||||
cache.set(item, factory(item.id));
|
||||
return cache.get(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an an element, if `key` of an element in the collection
|
||||
* with exact `value` can be found.
|
||||
* Otherwise null is returned.
|
||||
* @param key
|
||||
* @param value
|
||||
* @returns {*}
|
||||
*/
|
||||
getBy(key, value) {
|
||||
if (key === "id" && this._valueGetter) {
|
||||
var item = this._valueGetter(value);
|
||||
if (!item) return null;
|
||||
return this._getOrCreateInterface(item);
|
||||
}
|
||||
|
||||
for (var item of this._valuesGetter()) {
|
||||
if (item[key] != value) continue;
|
||||
return this._getOrCreateInterface(item);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an element with requested `id`, if exists in the collection.
|
||||
* Otherwise null is returned.
|
||||
* @param {String} id
|
||||
* @returns {*}
|
||||
*/
|
||||
get(id) { return this.getBy("id", id); }
|
||||
|
||||
*[Symbol.iterator]() {
|
||||
for (var item of this._valuesGetter()) {
|
||||
yield this._getOrCreateInterface(item);
|
||||
}
|
||||
}
|
||||
|
||||
_getRawItemBy(key, value) {
|
||||
for (var item of this._valuesGetter()) {
|
||||
if (item[key] != value) continue;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
*_getRawIterator() {
|
||||
for (var item of this._valuesGetter()) {
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
_getRaw(id) { return this._getRawItemBy("id", id); }
|
||||
|
||||
/**
|
||||
* Creates a new array with all elements that pass the test implemented
|
||||
* by the provided function.
|
||||
* @param {Function} fn - Function with signature fn(item)
|
||||
* @returns {Array}
|
||||
*/
|
||||
filter(condition) {
|
||||
if (typeof condition !== "function") {
|
||||
throw new TypeError("condition is not a function");
|
||||
}
|
||||
const items = [];
|
||||
for (var item of this) {
|
||||
if (condition(item))
|
||||
items.push(item);
|
||||
}
|
||||
return items;
|
||||
}
|
||||
concat(collection) {
|
||||
if (collection == null) {
|
||||
throw new TypeError("collection is null or not defined");
|
||||
}
|
||||
if (typeof collection.filter !== "function") {
|
||||
throw new TypeError();
|
||||
}
|
||||
collection = collection.filter(() => true);
|
||||
return this.filter(() => true).concat(collection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value in the collection, if an element in the collection
|
||||
* satisfies the provided testing function. Otherwise null is returned.
|
||||
* @param {Function} fn - Function with signature fn(item)
|
||||
* @returns {Object|null}
|
||||
*/
|
||||
find(condition) {
|
||||
if (typeof condition !== "function") {
|
||||
throw new TypeError("condition is not a function");
|
||||
}
|
||||
for (var item of this) {
|
||||
if (condition(item))
|
||||
return item;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a provided function once per element.
|
||||
* @param {Function} fn - Function with signature fn(item)
|
||||
*/
|
||||
forEach(fn) {
|
||||
if (typeof fn !== "function") {
|
||||
throw new TypeError("fn is not a function");
|
||||
}
|
||||
for (var item of this) {
|
||||
fn(item);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array with the results of calling a provided function on
|
||||
* every element in this collection.
|
||||
* @param {Function} fn - Function with signature fn(item)
|
||||
* @returns {Array}
|
||||
*/
|
||||
map(fn) {
|
||||
if (typeof fn !== "function") {
|
||||
throw new TypeError("fn is not a function");
|
||||
}
|
||||
const items = [];
|
||||
for (var item of this) {
|
||||
items.push(fn(item));
|
||||
}
|
||||
return items;
|
||||
}
|
||||
|
||||
inspect() {
|
||||
var copy = new (
|
||||
// create fake object to preserve class name
|
||||
new Function("return function " + this.constructor.name + "(){}")()
|
||||
);
|
||||
copy.length = this.length;
|
||||
return copy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new array with elements of this collection.
|
||||
* @returns {Array}
|
||||
*/
|
||||
toArray() {
|
||||
const array = [];
|
||||
for (var item of this) {
|
||||
array.push(item);
|
||||
}
|
||||
return array;
|
||||
}
|
||||
toJSON() { return this.toArray(); }
|
||||
|
||||
/**
|
||||
* Number of elements in this collection.
|
||||
* @returns {Number}
|
||||
* @readonly
|
||||
*/
|
||||
get length() {
|
||||
var i = 0;
|
||||
for (var item of this._valuesGetter()) i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* Number of elements in this collection. Alias for `.length`.
|
||||
* @returns {Number}
|
||||
* @readonly
|
||||
*/
|
||||
get size() { return this.length; }
|
||||
}
|
||||
|
||||
module.exports = ICollectionBase;
|
589
node_modules/discordie/lib/interfaces/IDirectMessageChannel.js
generated
vendored
Normal file
589
node_modules/discordie/lib/interfaces/IDirectMessageChannel.js
generated
vendored
Normal file
@ -0,0 +1,589 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Endpoints = Constants.Endpoints;
|
||||
const ChannelTypes = Constants.ChannelTypes;
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const ITextChannel = require("./ITextChannel");
|
||||
const ICall = require("./ICall");
|
||||
const Utils = require("../core/Utils");
|
||||
const Channel = require("../models/Channel");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model Channel
|
||||
* @extends IBase
|
||||
*/
|
||||
class IDirectMessageChannel extends IBase {
|
||||
constructor(discordie, directMessageChannelId) {
|
||||
super();
|
||||
Utils.definePrivate(this, {
|
||||
_discordie: discordie,
|
||||
_directMessageChannelId: directMessageChannelId,
|
||||
_call: new ICall(discordie, directMessageChannelId)
|
||||
});
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* **Deprecated**: Removed in API v6. Use `isPrivate` instead.
|
||||
* @return {boolean|null}
|
||||
* @readonly
|
||||
*/
|
||||
get is_private() {
|
||||
return this.isPrivate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a direct message channel or a group.
|
||||
* @return {boolean|null}
|
||||
* @readonly
|
||||
*/
|
||||
get isPrivate() {
|
||||
if (!this._valid) return null;
|
||||
return this._discordie._channels._isPrivate(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a voice channel in a guild.
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isGuildVoice() {
|
||||
return this.type === ChannelTypes.GUILD_VOICE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a text channel in a guild.
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isGuildText() {
|
||||
return this.type === ChannelTypes.GUILD_TEXT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a direct message channel (non-group).
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isDM() {
|
||||
return this.type === ChannelTypes.DM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this channel is a group direct message channel.
|
||||
* @return {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isGroupDM() {
|
||||
return this.type === ChannelTypes.GROUP_DM;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owner of the private channel.
|
||||
*
|
||||
* Returns null if the owner user is not in cache or there is no owner.
|
||||
* @returns {IAuthenticatedUser|IUser|null}
|
||||
* @readonly
|
||||
*/
|
||||
get owner() {
|
||||
if (!this.owner_id) return null;
|
||||
const owner = this._discordie.Users.get(this.owner_id);
|
||||
if (!owner) return null;
|
||||
if (this._discordie.User.equals(owner))
|
||||
return this._discordie.User;
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the `user` is the owner of the private channel.
|
||||
* @param {IGuildMember|IUser|IAuthenticatedUser|String} user
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isOwner(user) {
|
||||
if (!user) return false;
|
||||
if (!this.owner_id) return false;
|
||||
return this.owner_id === user.valueOf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string URL of image icon of this channel.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get iconURL() {
|
||||
if (!this.icon) return null;
|
||||
return Constants.CDN_ENDPOINT + Endpoints.CDN_DM_ICON(this.id, this.icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets first recipient of this channel.
|
||||
*
|
||||
* Returns null if this channel is invalid or has no recipients.
|
||||
*
|
||||
* **Deprecated**: Use `recipients` instead.
|
||||
* @returns {IUser|null}
|
||||
* @readonly
|
||||
*/
|
||||
get recipient() {
|
||||
if (!this._valid) return null;
|
||||
return this.recipients[0] || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether all messages were loaded.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get allMessagesLoaded() {
|
||||
return !this._discordie._messages.channelHasMore(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of cached messages in this channel, sorted in order of
|
||||
* arrival (message cache is sorted on message insertion, not when this
|
||||
* getter is invoked).
|
||||
*
|
||||
* Returns an empty array if channel no longer exists.
|
||||
* @returns {Array<IMessage>}
|
||||
* @readonly
|
||||
*/
|
||||
get messages() {
|
||||
return this._discordie.Messages.forChannel(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to fetch messages for this channel.
|
||||
*
|
||||
* Discord API does not allow fetching more than 100 messages at once.
|
||||
*
|
||||
* Promise resolves with an Object with following structure:
|
||||
* ```js
|
||||
* {
|
||||
* messages: Array<IMessage>,
|
||||
* limit: Number, // same as parameter passed or default value
|
||||
* before: String | null, // message id
|
||||
* after: String | null // message id
|
||||
* }
|
||||
* ```
|
||||
* @param {Number|null} [limit] - Default is 100
|
||||
* @param {IMessage|String|null} [before] - Message or message id
|
||||
* @param {IMessage|String|null} [after] - Message or message id
|
||||
* @returns {Promise<Object, Error>}
|
||||
* @example
|
||||
* var guild = client.Guilds.find(g => g.name == "test");
|
||||
* var channel = guild.generalChannel;
|
||||
*
|
||||
* // simple fetch:
|
||||
* channel.fetchMessages().then(() => {
|
||||
* console.log("[simple] messages in cache: " + channel.messages.length);
|
||||
* });
|
||||
*
|
||||
* // fetching more than 100 messages into cache sequentially:
|
||||
* fetchMessagesEx(channel, 420).then(() => {
|
||||
* console.log("[extended] messages in cache: " + channel.messages.length);
|
||||
* });
|
||||
*
|
||||
* // fetch more messages just like Discord client does
|
||||
* function fetchMessagesEx(channel, left) {
|
||||
* // message cache is sorted on insertion
|
||||
* // channel.messages[0] will get oldest message
|
||||
* var before = channel.messages[0];
|
||||
* return channel.fetchMessages(Math.min(left, 100), before)
|
||||
* .then(e => onFetch(e, channel, left));
|
||||
* }
|
||||
* function onFetch(e, channel, left) {
|
||||
* if (!e.messages.length) return Promise.resolve();
|
||||
* left -= e.messages.length;
|
||||
* console.log(`Received ${e.messages.length}, left: ${left}`);
|
||||
* if (left <= 0) return Promise.resolve();
|
||||
* return fetchMessagesEx(channel, left);
|
||||
* }
|
||||
*/
|
||||
fetchMessages(limit, before, after) {
|
||||
return ITextChannel.prototype.fetchMessages.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of cached pinned messages in this channel.
|
||||
*
|
||||
* Pinned message cache is updated only if all pinned messages have been
|
||||
* loaded with `IDirectMessageChannel.fetchPinned()`.
|
||||
*
|
||||
* Returns an empty array if channel no longer exists or if pinned messages
|
||||
* have not been fetched yet.
|
||||
* @returns {Array<IMessage>}
|
||||
* @readonly
|
||||
*/
|
||||
get pinnedMessages() {
|
||||
return this._discordie.Messages.forChannelPinned(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to fetch pinned messages for this channel.
|
||||
*
|
||||
* Promise resolves with an Object with following structure:
|
||||
* ```js
|
||||
* {
|
||||
* channelId: String,
|
||||
* messages: Array<IMessage>
|
||||
* }
|
||||
* ```
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
fetchPinned() {
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).channels.getPinnedMessages(this.id)
|
||||
.then(e => {
|
||||
e.messages = e.messages
|
||||
.map(msg => this._discordie.Messages.get(msg.id));
|
||||
return rs(e);
|
||||
})
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to send a message to this channel. Messages over 2000
|
||||
* characters will be rejected by the server.
|
||||
*
|
||||
* Use `uploadFile` if you want to send a message with an attachment.
|
||||
* @param {String|Array<String>} content
|
||||
* Strings will be sent as is, arrays - joined with a newline character.
|
||||
* @param {IUser|IGuildMember|Array<IUser>|Array<IGuildMember>} [mentions]
|
||||
* Deprecated: left for backward compatibility.
|
||||
* @param {boolean} [tts]
|
||||
* @param {Object} [embed]
|
||||
* Refer to [official API documentation](https://discordapp.com/developers/docs/resources/channel#embed-object)
|
||||
* for embed structure description.
|
||||
* @returns {Promise<IMessage, Error>}
|
||||
* @example
|
||||
* var guild = client.Guilds.find(g => g.name == "test");
|
||||
* if (!guild) return console.log("invalid guild");
|
||||
*
|
||||
* var channel = guild.generalChannel;
|
||||
*
|
||||
* channel.sendMessage("regular message");
|
||||
* channel.sendMessage("test with tts", true);
|
||||
*
|
||||
* var user = client.Users.find(u => u.username == "test");
|
||||
* if (!user) return console.log("invalid user");
|
||||
*
|
||||
* channel.sendMessage("mentioning user " + user.mention);
|
||||
* channel.sendMessage("@everyone or @here mention if you have permissions");
|
||||
*
|
||||
* channel.sendMessage("message with an embed", false, {
|
||||
* color: 0x3498db,
|
||||
* author: {name: "author name"},
|
||||
* title: "This is an embed",
|
||||
* url: "http://google.com",
|
||||
* timestamp: "2016-11-13T03:43:32.127Z",
|
||||
* fields: [{name: "some field", value: "some value"}],
|
||||
* footer: {text: "footer text"}
|
||||
* });
|
||||
*/
|
||||
sendMessage(content, mentions, tts, embed) {
|
||||
return ITextChannel.prototype.sendMessage.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to upload data to this channel.
|
||||
* Images require a `filename` with a valid extension to actually be uploaded.
|
||||
* @param {Buffer|ReadableStream|String} readableStream
|
||||
* Data to upload or filename as a string
|
||||
* @param {String} filename
|
||||
* Actual filename to show, required for non-string `readableStream`
|
||||
* @param {String} [content] - Additional comment message for attachment
|
||||
* @param {boolean} [tts]
|
||||
* @returns {Promise<IMessage, Error>}
|
||||
* @example
|
||||
* channel.uploadFile(fs.readFileSync("test.png"), "test.png"); // Buffer
|
||||
* channel.uploadFile(fs.createReadStream("test.png"), "test.png"); // Stream
|
||||
* channel.uploadFile("test.png"); // File
|
||||
* channel.uploadFile("test.png", null, "file with message");
|
||||
* channel.uploadFile("test.png", null, "file with message and tts", true);
|
||||
*/
|
||||
uploadFile(readableStream, filename, content, mentions, tts) {
|
||||
return ITextChannel.prototype.uploadFile.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to send typing status for this channel.
|
||||
*
|
||||
* Discord client displays it for 10 seconds, sends every 5 seconds.
|
||||
* Stops showing typing status if receives a message from the user.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
sendTyping() {
|
||||
return ITextChannel.prototype.sendTyping.apply(this, arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to close this channel (direct message channels only).
|
||||
* @returns {Promise}
|
||||
*/
|
||||
close() {
|
||||
return rest(this._discordie).channels.deleteChannel(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to ring specified recipients.
|
||||
* Has no effect if call has not started yet.
|
||||
*
|
||||
* Bot accounts cannot use this endpoint.
|
||||
* @param {Array<IUser|String>} [recipients]
|
||||
* @return {Promise}
|
||||
*/
|
||||
ring(recipients) {
|
||||
if (recipients && !Array.isArray(recipients))
|
||||
throw new TypeError("Param 'recipients' is not an array");
|
||||
|
||||
if (recipients) recipients = recipients.map(u => u.valueOf());
|
||||
return rest(this._discordie).channels.calls
|
||||
.ring(this.id, recipients);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to decline an incoming call (if no arguments passed) or
|
||||
* stop ringing for specified recipients.
|
||||
*
|
||||
* Bot accounts cannot use this endpoint.
|
||||
* @param {Array<IUser|String>} [recipients]
|
||||
* @return {Promise}
|
||||
*/
|
||||
stopRinging(recipients) {
|
||||
if (recipients && !Array.isArray(recipients))
|
||||
throw new TypeError("Param 'recipients' is not an array");
|
||||
|
||||
if (recipients) recipients = recipients.map(u => u.valueOf());
|
||||
return rest(this._discordie).channels.calls
|
||||
.stopRinging(this.id, recipients);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to change the server region hosting the call.
|
||||
*
|
||||
* Bot accounts cannot use this endpoint.
|
||||
* @param {String} region
|
||||
* @return {Promise}
|
||||
*/
|
||||
changeCallRegion(region) {
|
||||
return rest(this._discordie).channels.calls.changeRegion(this.id, region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to add a user to this private channel.
|
||||
*
|
||||
* Bot accounts cannot use this endpoint.
|
||||
* @param {IUser|IGuildMember} user
|
||||
* @return {Promise}
|
||||
*/
|
||||
addRecipient(user) {
|
||||
user = user.valueOf();
|
||||
return rest(this._discordie).channels.dm.addRecipient(this.id, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to remove a user from this private channel.
|
||||
*
|
||||
* Bot accounts cannot use this endpoint.
|
||||
* @param {IUser|IGuildMember} user
|
||||
* @return {Promise}
|
||||
*/
|
||||
removeRecipient(user) {
|
||||
user = user.valueOf();
|
||||
return rest(this._discordie).channels.dm.removeRecipient(this.id, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to set a name for this private channel.
|
||||
* @param {String} name
|
||||
* @return {Promise<IDirectMessageChannel, Error>}
|
||||
*/
|
||||
setName(name) {
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).channels.dm.setName(this.id, name)
|
||||
.then(() => rs(this))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to set an icon for this private channel.
|
||||
* @param {String|Buffer|null} icon
|
||||
* @return {Promise<IDirectMessageChannel, Error>}
|
||||
*/
|
||||
setIcon(icon) {
|
||||
if (icon instanceof Buffer) {
|
||||
icon = Utils.imageToDataURL(icon);
|
||||
} else if (icon === undefined) {
|
||||
icon = this.icon;
|
||||
}
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).channels.dm.setIcon(this.id, icon)
|
||||
.then(() => rs(this))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates or joins a call.
|
||||
* Only one call can be connected at the same time.
|
||||
*
|
||||
* Joining calls with bot accounts is not supported.
|
||||
* @param {boolean} [selfMute]
|
||||
* @param {boolean} [selfDeaf]
|
||||
* @returns {Promise<VoiceConnectionInfo, Error|Number>}
|
||||
*/
|
||||
joinCall(selfMute, selfDeaf) {
|
||||
selfMute = !!selfMute;
|
||||
selfDeaf = !!selfDeaf;
|
||||
|
||||
if (!this._valid)
|
||||
return Promise.reject(new Error("Channel does not exist"));
|
||||
|
||||
const call = this._discordie._calls.get(this._directMessageChannelId);
|
||||
if (call && call.unavailable)
|
||||
return Promise.reject(new Error("Call is unavailable"));
|
||||
|
||||
if (this._discordie._user && this._discordie._user.bot)
|
||||
throw new Error("Joining calls with bot accounts is not supported");
|
||||
|
||||
const vc = this._discordie.VoiceConnections;
|
||||
return vc._getOrCreate(null, this.id, selfMute, selfDeaf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves call if joined.
|
||||
*/
|
||||
leaveCall() {
|
||||
const info = this.getVoiceConnectionInfo();
|
||||
if (info) return info.voiceConnection.disconnect();
|
||||
|
||||
this._discordie.VoiceConnections
|
||||
.cancelIfPending(null, this._directMessageChannelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves `VoiceConnectionInfo` for the call of this channel.
|
||||
* @returns {VoiceConnectionInfo|null}
|
||||
*/
|
||||
getVoiceConnectionInfo() {
|
||||
return this._discordie.VoiceConnections
|
||||
.getForChannel(this._directMessageChannelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether current user is in the call.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get joinedCall() {
|
||||
const vc = this._discordie.VoiceConnections;
|
||||
const pendingChannel = vc.getPendingChannel(null);
|
||||
const channelId = this._directMessageChannelId;
|
||||
return !!(pendingChannel && pendingChannel === channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of users in the call.
|
||||
*
|
||||
* Returns null if call does not exist in cache or has not started yet.
|
||||
* @returns {Array<IUser>|null}
|
||||
* @readonly
|
||||
*/
|
||||
get usersInCall() {
|
||||
const call = this._discordie._calls.get(this._directMessageChannelId);
|
||||
return this._discordie.Users.usersInCall(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets call from cache.
|
||||
*
|
||||
* Returns null if call does not exist in cache or has not started yet.
|
||||
* @returns {ICall|null}
|
||||
* @readonly
|
||||
*/
|
||||
get call() {
|
||||
const call = this._discordie._calls.get(this._directMessageChannelId);
|
||||
return call ? this._call : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches call info through gateway socket.
|
||||
*
|
||||
* Currently there are no ways to fetch call info for all channels at once.
|
||||
* @return {Promise<ICall|null, Error>}
|
||||
*/
|
||||
fetchCall() {
|
||||
const gateway = this._discordie.gatewaySocket;
|
||||
if (!gateway || !gateway.connected)
|
||||
return Promise.reject(new Error("No gateway socket (not connected)"));
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
const call = this._discordie._calls.get(this._directMessageChannelId);
|
||||
if (call) return rs(this._call);
|
||||
|
||||
gateway.callConnect(this._directMessageChannelId);
|
||||
|
||||
setTimeout(() => {
|
||||
const call = this._discordie._calls.get(this._directMessageChannelId);
|
||||
rs(call ? this._call : null);
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
IDirectMessageChannel._inherit(Channel, function modelPropertyGetter(key) {
|
||||
return this._discordie._channels.get(this._directMessageChannelId)[key];
|
||||
});
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IDirectMessageChannel
|
||||
* @name name
|
||||
* @returns {String}
|
||||
*/
|
||||
IDirectMessageChannel._setValueOverride("name", function(name) {
|
||||
const UNNAMED = "Unnamed";
|
||||
if (!this._valid) return UNNAMED;
|
||||
|
||||
const type = this.type;
|
||||
if (type === ChannelTypes.DM) {
|
||||
const recipient = this.recipients[0];
|
||||
return recipient ? recipient.username : name;
|
||||
}
|
||||
if (type === ChannelTypes.GROUP_DM) {
|
||||
return name || this.recipients.map(u => u.username).join(", ") || UNNAMED;
|
||||
}
|
||||
|
||||
return name;
|
||||
});
|
||||
|
||||
/**
|
||||
* Gets recipients of this channel.
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IDirectMessageChannel
|
||||
* @name recipients
|
||||
* @returns {Array<IUser>|null}
|
||||
*/
|
||||
IDirectMessageChannel._setValueOverride("recipients", function(recipients) {
|
||||
const users = [];
|
||||
if (!recipients) return users;
|
||||
for (let id of recipients.values()) {
|
||||
const user = this._discordie.Users.get(id);
|
||||
if (user) users.push(user);
|
||||
}
|
||||
return users;
|
||||
});
|
||||
|
||||
|
||||
module.exports = IDirectMessageChannel;
|
72
node_modules/discordie/lib/interfaces/IDirectMessageChannelCollection.js
generated
vendored
Normal file
72
node_modules/discordie/lib/interfaces/IDirectMessageChannelCollection.js
generated
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
"use strict";
|
||||
|
||||
const ICollectionBase = require("./ICollectionBase");
|
||||
const IDirectMessageChannel = require("./IDirectMessageChannel");
|
||||
const Utils = require("../core/Utils");
|
||||
const Constants = require("../Constants");
|
||||
const ChannelTypes = Constants.ChannelTypes;
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @extends ICollectionBase
|
||||
*/
|
||||
class IDirectMessageChannelCollection extends ICollectionBase {
|
||||
constructor(discordie, valuesGetter, valueGetter) {
|
||||
super({
|
||||
valuesGetter: valuesGetter,
|
||||
valueGetter: valueGetter,
|
||||
itemFactory: (id) => new IDirectMessageChannel(this._discordie, id)
|
||||
});
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a DM channel from cache or makes a request to create one.
|
||||
* @param {IUser|IGuildMember|String} recipient
|
||||
* @returns {Promise<IDirectMessageChannel, Error>}
|
||||
*/
|
||||
getOrOpen(recipient) {
|
||||
const existing = this.find(c =>
|
||||
c.type === ChannelTypes.DM &&
|
||||
c.recipients.length === 1 &&
|
||||
c.recipients[0].equals(recipient)
|
||||
);
|
||||
if (existing)
|
||||
return Promise.resolve(existing);
|
||||
return this.open(recipient);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create a DM channel.
|
||||
* @param {IUser|IGuildMember|String} recipient
|
||||
* @returns {Promise<IDirectMessageChannel, Error>}
|
||||
*/
|
||||
open(recipient) {
|
||||
recipient = recipient.valueOf();
|
||||
return this.createGroupDM([recipient]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create a group DM channel.
|
||||
*
|
||||
* Bot accounts cannot use this endpoint.
|
||||
* @param {Array<IUser|IGuildMember|String>} [recipients]
|
||||
* @returns {Promise<IDirectMessageChannel, Error>}
|
||||
*/
|
||||
createGroupDM(recipients) {
|
||||
recipients = recipients || [];
|
||||
recipients = recipients.filter(u => u).map(u => u.valueOf());
|
||||
const userId = this._discordie.User.id;
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.users.createDirectMessageChannel(userId, recipients)
|
||||
.then(c => rs(this._discordie.DirectMessageChannels.get(c.id)))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IDirectMessageChannelCollection;
|
542
node_modules/discordie/lib/interfaces/IGuild.js
generated
vendored
Normal file
542
node_modules/discordie/lib/interfaces/IGuild.js
generated
vendored
Normal file
@ -0,0 +1,542 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Endpoints = Constants.Endpoints;
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const IChannel = require("./IChannel");
|
||||
const IGuildMember = require("./IGuildMember");
|
||||
const IUser = require("./IUser");
|
||||
const IRole = require("./IRole");
|
||||
const Utils = require("../core/Utils");
|
||||
const Guild = require("../models/Guild");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model Guild
|
||||
* @extends IBase
|
||||
*/
|
||||
class IGuild extends IBase {
|
||||
constructor(discordie, guildId) {
|
||||
super();
|
||||
Utils.definePrivate(this, {
|
||||
_discordie: discordie,
|
||||
_guildId: guildId
|
||||
});
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an acronym string for this guild.
|
||||
* (Text that shows up as guild icon in the client if there is no image icon.)
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
*/
|
||||
get acronym() {
|
||||
if (!this.name) return "";
|
||||
return this.name.replace(/\w+/g, match => match[0]).replace(/\s/g, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string URL of image icon of this guild.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get iconURL() {
|
||||
if (!this.icon) return null;
|
||||
return Constants.CDN_ENDPOINT +
|
||||
Endpoints.CDN_GUILD_ICON(this.id, this.icon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string URL of invite splash image of this guild.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get splashURL() {
|
||||
if (!this.splash) return null;
|
||||
return Constants.CDN_ENDPOINT +
|
||||
Endpoints.CDN_GUILD_SPLASH(this.id, this.splash);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the `user` is the owner of this guild.
|
||||
* @param {IGuildMember|IUser|IAuthenticatedUser|String} user
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isOwner(user) {
|
||||
if (!user) return false;
|
||||
if (!this.owner_id) return false;
|
||||
return this.owner_id === user.valueOf();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns afk channel of this guild.
|
||||
* @returns {IChannel|null}
|
||||
* @readonly
|
||||
*/
|
||||
get afk_channel() {
|
||||
if (!this.afk_channel_id) return null;
|
||||
const afk_channel = this._discordie.Channels.get(this.afk_channel_id);
|
||||
return afk_channel ? afk_channel : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the owner of this guild.
|
||||
*
|
||||
* Returns null if the owner user is not in cache.
|
||||
*
|
||||
* See `.isOwner(user)` if you want to safely check if the `user` is owner.
|
||||
* @returns {IAuthenticatedUser|IUser|null}
|
||||
* @readonly
|
||||
*/
|
||||
get owner() {
|
||||
if (!this.owner_id) return null;
|
||||
const owner = this._discordie.Users.get(this.owner_id);
|
||||
if (!owner) return null;
|
||||
if (this._discordie.User.equals(owner))
|
||||
return this._discordie.User;
|
||||
return owner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of text and voice channels of this guild.
|
||||
* @returns {Array<IChannel>}
|
||||
* @readonly
|
||||
*/
|
||||
get channels() {
|
||||
return this._discordie.Channels.forGuild(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of text channels of this guild.
|
||||
* @returns {Array<ITextChannel>}
|
||||
* @readonly
|
||||
*/
|
||||
get textChannels() {
|
||||
return this._discordie.Channels.textForGuild(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of voice channels of this guild.
|
||||
* @returns {Array<IVoiceChannel>}
|
||||
* @readonly
|
||||
*/
|
||||
get voiceChannels() {
|
||||
return this._discordie.Channels.voiceForGuild(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns general channel of this guild.
|
||||
* @returns {ITextChannel}
|
||||
* @readonly
|
||||
*/
|
||||
get generalChannel() {
|
||||
return this._discordie.Channels.get(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to edit this guild,
|
||||
* substituting `undefined` or `null` properties with current values.
|
||||
*
|
||||
* Passing `null` in `icon` or `afkChannelId` will remove current
|
||||
* icon/channel. Use `undefined` instead of `null` in this case.
|
||||
* @param {String} [name]
|
||||
* @param {String|Buffer|null} [icon]
|
||||
* @param {String} [region]
|
||||
* @param {IChannel|String|null} [afkChannelId] - Channel or an id string
|
||||
* @param {Number} [afkTimeout] - 60, 300, 900, 1800 or 3600 seconds
|
||||
* @param {Number} [verificationLevel]
|
||||
* See Discordie.VerificationLevel
|
||||
* @param {Number} [defaultMessageNotifications]
|
||||
* See Discordie.UserNotificationSettings
|
||||
* @returns {Promise<IGuild, Error>}
|
||||
*/
|
||||
edit(name, icon, region, afkChannelId, afkTimeout, verificationLevel,
|
||||
defaultMessageNotifications) {
|
||||
const guild = this._discordie._guilds.get(this._guildId);
|
||||
name = name || guild.name;
|
||||
region = region || guild.region;
|
||||
afkTimeout = afkTimeout || guild.afk_timeout;
|
||||
|
||||
const opt = (value, _) => value != null ? value : _;
|
||||
verificationLevel =
|
||||
opt(verificationLevel, guild.verification_level);
|
||||
defaultMessageNotifications =
|
||||
opt(defaultMessageNotifications, guild.default_message_notifications);
|
||||
|
||||
if (icon instanceof Buffer) {
|
||||
icon = Utils.imageToDataURL(icon);
|
||||
} else if (icon === undefined) {
|
||||
icon = guild.icon;
|
||||
}
|
||||
|
||||
if (afkChannelId === undefined) {
|
||||
afkChannelId = guild.afk_channel_id;
|
||||
} else if (afkChannelId != null) {
|
||||
afkChannelId = afkChannelId.valueOf();
|
||||
}
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.guilds.patchGuild(
|
||||
guild.id,
|
||||
name, icon, region,
|
||||
afkChannelId, afkTimeout,
|
||||
verificationLevel,
|
||||
defaultMessageNotifications
|
||||
)
|
||||
.then(() => rs(this))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create a channel in this guild.
|
||||
* @param {Number} type - See IChannel / Discordie.ChannelTypes
|
||||
* @param {String} name
|
||||
* @param {Array<IPermissionOverwrite>} [permissionOverwrites]
|
||||
* @param {Number} [bitrate] - Only for voice channels
|
||||
* @param {Number} [userLimit] - Only for voice channels
|
||||
* @returns {Promise<ITextChannel|IVoiceChannel, Error>}
|
||||
*/
|
||||
createChannel(type, name, permissionOverwrites, bitrate, userLimit) {
|
||||
permissionOverwrites = permissionOverwrites || [];
|
||||
if (!Array.isArray(permissionOverwrites))
|
||||
throw TypeError("Param 'permissionOverwrites' must be an array");
|
||||
|
||||
permissionOverwrites = permissionOverwrites.map(v => {
|
||||
return typeof v.getRaw === "function" ? v.getRaw() : null;
|
||||
}).filter(v => v);
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.channels.createChannel(this.id,
|
||||
type, name, permissionOverwrites, bitrate, userLimit
|
||||
)
|
||||
.then(channel => rs(this._discordie.Channels.get(channel.id)))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create a role in this guild.
|
||||
* @returns {Promise<IRole, Error>}
|
||||
*/
|
||||
createRole() {
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).guilds.roles.createRole(this.id)
|
||||
.then(role => rs(new IRole(this._discordie, role.id, this.id)))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create an invite for general channel in this guild.
|
||||
*
|
||||
* See `IChannel.createInvite` for more info.
|
||||
* @see IChannel.createInvite
|
||||
* @param {Object} options
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
createInvite(options) {
|
||||
return this._discordie.Invites.create(this.generalChannel, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array containing members of this guild.
|
||||
* @returns {Array<IGuildMember>}
|
||||
* @readonly
|
||||
*/
|
||||
get members() {
|
||||
return this._discordie.Users.membersForGuild(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete this guild.
|
||||
*
|
||||
* Returns a rejected promise if the user **is not** owner.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
delete() {
|
||||
if (!this.owner.equals(this._discordie.User))
|
||||
return Promise.reject();
|
||||
return rest(this._discordie).guilds.deleteGuild(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete this guild.
|
||||
*
|
||||
* Returns a rejected promise if the user **is** owner.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
leave() {
|
||||
if (this.owner.equals(this._discordie.User))
|
||||
return Promise.reject();
|
||||
return rest(this._discordie).guilds.leaveGuild(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to ban a user (does not have to be a member of the guild).
|
||||
*
|
||||
* Additionally delete `deleteMessageForDays` number of days worth of their
|
||||
* messages from all channels of the guild.
|
||||
* @param {IUser|String} user - User or an id string
|
||||
* @param deleteMessageForDays - Number of days worth of messages to delete
|
||||
* (min 0, max 7)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
ban(user, deleteMessageForDays) {
|
||||
user = user.valueOf();
|
||||
return rest(this._discordie)
|
||||
.guilds.bans.banMember(this.id, user, deleteMessageForDays);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to unban a user.
|
||||
* @param {IUser|String} user - User or an id string
|
||||
* @returns {Promise}
|
||||
*/
|
||||
unban(user) {
|
||||
user = user.valueOf();
|
||||
return rest(this._discordie).guilds.bans.unbanMember(this.id, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to get ban list of this guild.
|
||||
* @returns {Promise<Array<IUser>, Error>}
|
||||
*/
|
||||
getBans() {
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).guilds.bans.getBans(this.id)
|
||||
.then(bans => {
|
||||
const bannedUsers = bans.map(ban => {
|
||||
return new IUser(this._discordie, ban.user.id);
|
||||
});
|
||||
return rs(bannedUsers);
|
||||
})
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to get estimate of members affected by prune request.
|
||||
*
|
||||
* Promise resolves with an Object with following structure:
|
||||
* ```js
|
||||
* {
|
||||
* guildId: String,
|
||||
* days: Number, // same as parameter passed
|
||||
* estimate: Number
|
||||
* }
|
||||
* ```
|
||||
* @param {Number} days - Number of days from 1 to 7, default 1
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
getPruneEstimate(days) {
|
||||
return rest(this._discordie).guilds.prune.getPrune(this.id, days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to prune members.
|
||||
*
|
||||
* Promise resolves with an Object with following structure:
|
||||
* ```js
|
||||
* {
|
||||
* guildId: String,
|
||||
* days: Number, // same as parameter passed
|
||||
* pruned: Number
|
||||
* }
|
||||
* ```
|
||||
* @param {Number} days - Number of days from 1 to 7, default 1
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
pruneMembers(days) {
|
||||
// make it also accept object from .getPruneEstimate(days)
|
||||
if (days && days.hasOwnProperty("days")) {
|
||||
days = days.days;
|
||||
}
|
||||
return rest(this._discordie).guilds.prune.postPrune(this.id, days);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to get a list of invites of this guild.
|
||||
* @returns {Promise<Array<Object>, Error>}
|
||||
*/
|
||||
getInvites() {
|
||||
return rest(this._discordie).guilds.getInvites(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to get a list of voice regions available for this guild.
|
||||
* @returns {Promise<Array<Object>, Error>}
|
||||
*/
|
||||
fetchRegions() {
|
||||
return rest(this._discordie).voice.getRegions(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to transfer ownership of this guild to `user`.
|
||||
* @param {IGuildMember|IUser|String} user - User or an id string
|
||||
* @returns {Promise<IGuild, Error>}
|
||||
*/
|
||||
transferOwnership(user) {
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.guilds.transferOwnership(this.id, user.valueOf())
|
||||
.then(() => rs(this))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to get widget (external embed) settings.
|
||||
*
|
||||
* Promise resolves with an Object with following structure:
|
||||
* ```js
|
||||
* {
|
||||
* enabled: boolean,
|
||||
* channel_id: String|null
|
||||
* }
|
||||
* ```
|
||||
* @return {Promise<Object, Error>}
|
||||
*/
|
||||
getWidget() {
|
||||
return rest(this._discordie).guilds.getEmbed(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to set widget (external embed) settings.
|
||||
* @param {Object} options
|
||||
* Object `{enabled: boolean, channelId or channel_id: String}`.
|
||||
* Both options are optional.
|
||||
* @return {Promise<Object, Error>}
|
||||
*/
|
||||
editWidget(options) {
|
||||
return rest(this._discordie).guilds.patchEmbed(this.id, options || {});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to fetch emojis for this guild.
|
||||
*
|
||||
* Only user and whitelisted bot accounts can use this endpoint.
|
||||
*
|
||||
* Promise resolves with an array of Objects with following structure:
|
||||
* ```js
|
||||
* {
|
||||
* "managed": false,
|
||||
* "name": 'abc',
|
||||
* "roles": [],
|
||||
* "user": {
|
||||
* "username": "testuser",
|
||||
* "discriminator": "3273",
|
||||
* "id": "000000000000000000",
|
||||
* "avatar": null
|
||||
* },
|
||||
* "require_colons": true,
|
||||
* "id": "000000000000000000"
|
||||
* }
|
||||
* ```
|
||||
* @return {Promise<Array<Object>, Error>}
|
||||
*/
|
||||
fetchEmoji() {
|
||||
return rest(this._discordie).guilds.emoji.getEmoji(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create an emoji.
|
||||
*
|
||||
* Returned object does not contain `user` property.
|
||||
*
|
||||
* Only user and whitelisted bot accounts can use this endpoint.
|
||||
* @param {Buffer|String} image - Buffer or base64 image string
|
||||
* @param {String} name
|
||||
* @return {Promise<Object, Error>}
|
||||
*/
|
||||
uploadEmoji(image, name) {
|
||||
if (image instanceof Buffer) {
|
||||
image = Utils.imageToDataURL(image);
|
||||
}
|
||||
|
||||
return rest(this._discordie).guilds.emoji.postEmoji(this.id, image, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete the specified emoji.
|
||||
*
|
||||
* Only user and whitelisted bot accounts can use this endpoint.
|
||||
* @param {Object|String} emoji - Emoji object or an id string
|
||||
* @return {Promise<Object, Error>}
|
||||
*/
|
||||
deleteEmoji(emoji) {
|
||||
if (emoji && emoji.id) emoji = emoji.id;
|
||||
|
||||
return rest(this._discordie).guilds.emoji.deleteEmoji(this.id, emoji);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to edit the specified emoji.
|
||||
*
|
||||
* Returned object does not contain `user` property.
|
||||
*
|
||||
* Only user and whitelisted bot accounts can use this endpoint.
|
||||
* @param {Object|String} emoji - Emoji object or an id string
|
||||
* @param {Object} options
|
||||
* Optional properties to edit:
|
||||
* `{name: String, roles: Array<IRole>|Array<String>}`
|
||||
* @return {Promise<Object, Error>}
|
||||
*/
|
||||
editEmoji(emoji, options) {
|
||||
if (emoji && emoji.id) emoji = emoji.id;
|
||||
if (!options) return Promise.resolve();
|
||||
|
||||
options = Object.assign({}, options);
|
||||
|
||||
const roles = options.roles;
|
||||
if (roles && !Array.isArray(roles)) {
|
||||
throw new TypeError("Param 'roles' must be an array");
|
||||
}
|
||||
if (Array.isArray(roles)) {
|
||||
options.roles = roles.filter(role => role).map(role => role.valueOf());
|
||||
}
|
||||
|
||||
return rest(this._discordie)
|
||||
.guilds.emoji.patchEmoji(this.id, emoji, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a string URL of an emoji.
|
||||
* @returns {String|null}
|
||||
*/
|
||||
getEmojiURL(emoji) {
|
||||
if (emoji && emoji.id) emoji = emoji.id;
|
||||
if (!emoji) return null;
|
||||
return Constants.CDN_ENDPOINT + Endpoints.CDN_EMOJI(emoji);
|
||||
}
|
||||
}
|
||||
|
||||
IGuild._inherit(Guild, function modelPropertyGetter(key) {
|
||||
return this._discordie._guilds.get(this._guildId)[key];
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates an array of roles of this guild.
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IGuild
|
||||
* @name roles
|
||||
* @returns {Array<IRole>}
|
||||
*/
|
||||
IGuild._setValueOverride("roles", function(rolesRaw) {
|
||||
const roles = [];
|
||||
if (!rolesRaw) return roles;
|
||||
for (let role of rolesRaw.values()) {
|
||||
roles.push(new IRole(this._discordie, role.id, this.id));
|
||||
}
|
||||
return roles;
|
||||
});
|
||||
|
||||
module.exports = IGuild;
|
78
node_modules/discordie/lib/interfaces/IGuildCollection.js
generated
vendored
Normal file
78
node_modules/discordie/lib/interfaces/IGuildCollection.js
generated
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
"use strict";
|
||||
|
||||
const ICollectionBase = require("./ICollectionBase");
|
||||
const IGuild = require("./IGuild");
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @extends ICollectionBase
|
||||
*/
|
||||
class IGuildCollection extends ICollectionBase {
|
||||
constructor(discordie, valuesGetter, valueGetter) {
|
||||
super({
|
||||
valuesGetter: valuesGetter,
|
||||
valueGetter: valueGetter,
|
||||
itemFactory: (id) => new IGuild(this._discordie, id)
|
||||
});
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create a guild.
|
||||
* @param {String} name
|
||||
* @param {String} region
|
||||
* @param {Buffer|null} [icon]
|
||||
* @param {Array<IRole|Object>} [roles]
|
||||
* @param {Array<IChannel|Object>} [channels]
|
||||
* @param {Number} [verificationLevel]
|
||||
* See Discordie.VerificationLevel
|
||||
* @param {Number} [defaultMessageNotifications]
|
||||
* See Discordie.UserNotificationSettings
|
||||
* @returns {Promise<IGuild, Error>}
|
||||
*/
|
||||
create(name, region, icon,
|
||||
roles, channels,
|
||||
verificationLevel, defaultMessageNotifications) {
|
||||
if (icon instanceof Buffer) {
|
||||
icon = Utils.imageToDataURL(icon);
|
||||
}
|
||||
|
||||
const toRaw = (data, param) => {
|
||||
data = data || [];
|
||||
if (!Array.isArray(data))
|
||||
throw TypeError("Param '" + param + "' must be an array");
|
||||
|
||||
return data.map(v => {
|
||||
return typeof v.getRaw === "function" ? v.getRaw() : null;
|
||||
}).filter(v => v);
|
||||
};
|
||||
|
||||
roles = toRaw(roles, "roles");
|
||||
channels = toRaw(channels, "channels");
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).guilds.createGuild(
|
||||
name, region, icon,
|
||||
roles, channels,
|
||||
verificationLevel, defaultMessageNotifications
|
||||
)
|
||||
.then(guild => rs(this._discordie.Guilds.get(guild.id)))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to get a default list of voice regions.
|
||||
* Use IGuild.fetchRegions for getting guild-specific list.
|
||||
* @returns {Promise<Array<Object>, Error>}
|
||||
*/
|
||||
fetchRegions() {
|
||||
return rest(this._discordie).voice.getRegions();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IGuildCollection;
|
291
node_modules/discordie/lib/interfaces/IGuildMember.js
generated
vendored
Normal file
291
node_modules/discordie/lib/interfaces/IGuildMember.js
generated
vendored
Normal file
@ -0,0 +1,291 @@
|
||||
"use strict";
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const IUser = require("./IUser");
|
||||
const IRole = require("./IRole");
|
||||
const GuildMember = require("../models/GuildMember");
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model GuildMember
|
||||
* @extends IUser
|
||||
*/
|
||||
class IGuildMember extends IUser {
|
||||
constructor(discordie, userId, guildId) {
|
||||
super(discordie, userId);
|
||||
Utils.definePrivate(this, {_guildId: guildId});
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current status of the member.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
*/
|
||||
get status() {
|
||||
return this._discordie._presences.getStatus(this.id, this._guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current game the member is playing.
|
||||
* @returns {Object|null}
|
||||
* @readonly
|
||||
*/
|
||||
get game() {
|
||||
return this._discordie._presences.getGame(this.id, this._guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the current game the member is playing.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get gameName() {
|
||||
return this.game ? this.game.name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Previous status of the member.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
*/
|
||||
get previousStatus() {
|
||||
return this._discordie._presences.getPreviousStatus(this.id, this._guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Previous game the member was playing.
|
||||
* @returns {Object|null}
|
||||
* @readonly
|
||||
*/
|
||||
get previousGame() {
|
||||
return this._discordie._presences.getPreviousGame(this.id, this._guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the previous game the member was playing.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get previousGameName() {
|
||||
return this.previousGame ? this.previousGame.name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets guild of this member.
|
||||
* @returns {IGuild|null}
|
||||
* @readonly
|
||||
*/
|
||||
get guild() {
|
||||
return this._discordie.Guilds.get(this._guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets `nick` of this member if set, otherwise returns `username`.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get name() {
|
||||
return this.nick ? this.nick : this.username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first voice channel that this member is currently in.
|
||||
* @returns {IVoiceChannel|null}
|
||||
*/
|
||||
getVoiceChannel() {
|
||||
return super.getVoiceChannel(this._guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to kick this member (from the guild they belong to).
|
||||
* @returns {Promise}
|
||||
*/
|
||||
kick() {
|
||||
return rest(this._discordie)
|
||||
.guilds.members.kickMember(this._guildId, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to ban this member (from the guild they belong to).
|
||||
*
|
||||
* Additionally delete `deleteMessageForDays` number of days worth of their
|
||||
* messages from all channels of the guild.
|
||||
* @param deleteMessageForDays - Number of days worth of messages to delete
|
||||
* (min 0, max 7)
|
||||
* @returns {Promise}
|
||||
*/
|
||||
ban(deleteMessageForDays) {
|
||||
return rest(this._discordie)
|
||||
.guilds.bans.banMember(this._guildId, this._userId, deleteMessageForDays);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to unban this member (from the guild they belonged to).
|
||||
* @returns {Promise}
|
||||
*/
|
||||
unban() {
|
||||
return rest(this._discordie)
|
||||
.guilds.bans.unbanMember(this._guildId, this._userId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to mute this member globally in the guild.
|
||||
*
|
||||
* Returns a resolved promise if the member is already muted.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
serverMute(mute) {
|
||||
if (mute === undefined) mute = true;
|
||||
if (mute == this.mute) return Promise.resolve();
|
||||
return rest(this._discordie)
|
||||
.guilds.members.setMute(this._guildId, this.id, mute);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to unmute this member globally in the guild.
|
||||
*
|
||||
* Returns a resolved promise if the member is already unmuted.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
serverUnmute() {
|
||||
return this.serverMute(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to deafen this member globally in the guild.
|
||||
*
|
||||
* Returns a resolved promise if the member is already deafened.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
serverDeafen(deaf) {
|
||||
if (deaf === undefined) deaf = true;
|
||||
if (deaf == this.deaf) return Promise.resolve();
|
||||
return rest(this._discordie)
|
||||
.guilds.members.setDeaf(this._guildId, this.id, deaf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to undeafen this member globally in the guild.
|
||||
*
|
||||
* Returns a resolved promise if the member is already undeafened.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
serverUndeafen() {
|
||||
return this.serverDeafen(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this member has the specified role.
|
||||
* @param {IRole|String} role - Role or an id string
|
||||
* @returns {Promise}
|
||||
*/
|
||||
hasRole(role) {
|
||||
role = role.valueOf();
|
||||
return this.getRaw().roles.indexOf(role) >= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns (adds) the specified role to this member.
|
||||
* @param {IRole|String} role - Role or an id string
|
||||
* @returns {Promise}
|
||||
*/
|
||||
assignRole(role) {
|
||||
role = role.valueOf();
|
||||
const rawMember = this.getRaw();
|
||||
if (!rawMember || !rawMember.roles)
|
||||
return Promise.reject(new Error("Member does not exist"));
|
||||
// raw roles are mutable, copying with .slice()
|
||||
const roleIds = rawMember.roles.slice();
|
||||
const roleIndex = roleIds.indexOf(role);
|
||||
|
||||
if (roleIndex >= 0) return Promise.resolve();
|
||||
roleIds.push(role);
|
||||
|
||||
return rest(this._discordie)
|
||||
.guilds.members.setRoles(this._guildId, this.id, roleIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unassigns (removes) the specified role from this member.
|
||||
* @param {IRole|String} role - Role or an id string
|
||||
* @returns {Promise}
|
||||
*/
|
||||
unassignRole(role) {
|
||||
role = role.valueOf();
|
||||
const rawMember = this.getRaw();
|
||||
if (!rawMember || !rawMember.roles)
|
||||
return Promise.reject(new Error("Member does not exist"));
|
||||
// raw roles are mutable, copying with .slice()
|
||||
const roleIds = rawMember.roles.slice();
|
||||
const roleIndex = roleIds.indexOf(role);
|
||||
|
||||
if (roleIndex < 0) return Promise.resolve();
|
||||
roleIds.splice(roleIndex, 1);
|
||||
|
||||
return rest(this._discordie)
|
||||
.guilds.members.setRoles(this._guildId, this.id, roleIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets specified roles for this member: overwrites all existing roles
|
||||
* with a new set of roles.
|
||||
* @param {Array<IRole|String>} roles - Array of roles or id strings
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setRoles(roles) {
|
||||
const roleIds = roles.map(role => role.valueOf());
|
||||
return rest(this._discordie)
|
||||
.guilds.members.setRoles(this._guildId, this.id, roleIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves this member to the specified voice channel.
|
||||
* @param {IChannel|String} channel - Channel or an id string
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setChannel(channel) {
|
||||
channel = channel.valueOf();
|
||||
return rest(this._discordie)
|
||||
.guilds.members.setChannel(this._guildId, this.id, channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to set a nickname for this member.
|
||||
*
|
||||
* Requires permission `MANAGE_NICKNAMES`.
|
||||
* @param {String} nick
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setNickname(nick) {
|
||||
return rest(this._discordie)
|
||||
.guilds.members.setNickname(this._guildId, this.id, nick);
|
||||
}
|
||||
}
|
||||
|
||||
IGuildMember._inherit(GuildMember, function modelPropertyGetter(key) {
|
||||
return this._discordie._members.getMember(this._guildId, this._userId)[key];
|
||||
});
|
||||
|
||||
/**
|
||||
* Creates an array of roles assigned to this member.
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IGuildMember
|
||||
* @name roles
|
||||
* @returns {Array<IRole>}
|
||||
*/
|
||||
IGuildMember._setValueOverride("roles", function(roleIds) {
|
||||
const roles = [];
|
||||
if (!roleIds) return roles;
|
||||
for (let roleId of roleIds) {
|
||||
roles.push(new IRole(this._discordie, roleId, this._guildId));
|
||||
}
|
||||
return roles;
|
||||
});
|
||||
|
||||
module.exports = IGuildMember;
|
101
node_modules/discordie/lib/interfaces/IInviteManager.js
generated
vendored
Normal file
101
node_modules/discordie/lib/interfaces/IInviteManager.js
generated
vendored
Normal file
@ -0,0 +1,101 @@
|
||||
"use strict";
|
||||
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
class IInviteManager {
|
||||
constructor(discordie) {
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to create an invite.
|
||||
* See `IChannel.createInvite` for more info.
|
||||
* @see IChannel.createInvite
|
||||
* @param {IChannel|String} channel
|
||||
* @param {Object} options
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
create(channel, options) {
|
||||
options = options || {
|
||||
max_age: 60 * 30,
|
||||
// value in seconds
|
||||
max_uses: 0,
|
||||
// pretty obvious
|
||||
temporary: false
|
||||
// temporary membership, kicks members without roles on disconnect
|
||||
};
|
||||
channel = channel.valueOf();
|
||||
return rest(this._discordie).invites.createInvite(channel, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to regenerate existing invite.
|
||||
* @param {Object|String} code
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
regenerate(code) {
|
||||
if (code && code.code) code = code.code;
|
||||
const options = {regenerate: code};
|
||||
return rest(this._discordie).invites.createInvite(channel, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to revoke existing invite.
|
||||
* @param {Object|String} code
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
revoke(code) {
|
||||
if (code && code.code) code = code.code;
|
||||
return rest(this._discordie).invites.deleteInvite(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to resolve existing invite.
|
||||
* @param {Object|String} code
|
||||
* @returns {Promise<Object, Error>}
|
||||
* @example
|
||||
* client.Invites.resolve("Zt5yW").then(console.log).catch(console.log);
|
||||
* // Example response:
|
||||
* {
|
||||
* "code": "Zt5yW",
|
||||
* "guild": {
|
||||
* "splash_hash": null,
|
||||
* "id": "00000000000000000",
|
||||
* "name": "test"
|
||||
* },
|
||||
* "channel": {
|
||||
* "type": "text",
|
||||
* "id": "000000000000000000",
|
||||
* "name": "testchannel"
|
||||
* }
|
||||
* }
|
||||
*/
|
||||
resolve(code) {
|
||||
if (code && code.code) code = code.code;
|
||||
return rest(this._discordie).invites.getInvite(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* **Deprecated**: Only works with user accounts.
|
||||
* Bot accounts can be invited by users with Manage Server permission using
|
||||
* the `https://discordapp.com/oauth2/authorize?client_id=%APP_ID%&scope=bot`
|
||||
* page. See official Discord API documentation for more info.
|
||||
*
|
||||
* Makes a request to accept existing invite.
|
||||
* @param {Object|String} code
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
accept(code) {
|
||||
if (code && code.code) code = code.code;
|
||||
return rest(this._discordie).invites.postInvite(code);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IInviteManager;
|
430
node_modules/discordie/lib/interfaces/IMessage.js
generated
vendored
Normal file
430
node_modules/discordie/lib/interfaces/IMessage.js
generated
vendored
Normal file
@ -0,0 +1,430 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const MessageTypes = Constants.MessageTypes;
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const IRole = require("./IRole");
|
||||
const IUser = require("./IUser");
|
||||
const Utils = require("../core/Utils");
|
||||
const Message = require("../models/Message");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model Message
|
||||
* @extends IBase
|
||||
* @description
|
||||
* Chat message. Can be a system message depending on type:
|
||||
*
|
||||
* ```js
|
||||
* Discordie.MessageTypes: {
|
||||
* DEFAULT: 0,
|
||||
* RECIPIENT_ADD: 1,
|
||||
* RECIPIENT_REMOVE: 2,
|
||||
* CALL: 3,
|
||||
* CHANNEL_NAME_CHANGE: 4,
|
||||
* CHANNEL_ICON_CHANGE: 5,
|
||||
* CHANNEL_PINNED_MESSAGE: 6
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class IMessage extends IBase {
|
||||
constructor(discordie, messageId) {
|
||||
super();
|
||||
Utils.definePrivate(this, {
|
||||
_discordie: discordie,
|
||||
_messageId: messageId
|
||||
});
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this message is cached.
|
||||
* @param {IMessage} message
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isCached() {
|
||||
return !!this._valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this message was edited by the author.
|
||||
*
|
||||
* Returns null if message does not exist in cache.
|
||||
* @returns {boolean|null}
|
||||
* @readonly
|
||||
*/
|
||||
get isEdited() {
|
||||
return this.isCached ? this.edited_timestamp != null : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this message is from a private channel (direct message).
|
||||
*
|
||||
* Returns null if message/channel does not exist in cache.
|
||||
* @returns {boolean|null}
|
||||
* @readonly
|
||||
*/
|
||||
get isPrivate() {
|
||||
return this._discordie._channels.isPrivate(this.channel_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether the message is a system message.
|
||||
* @returns {boolean|null}
|
||||
* @readonly
|
||||
*/
|
||||
get isSystem() {
|
||||
return this.type !== MessageTypes.DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a system message string depending on message `type`.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get systemMessage() {
|
||||
if (!this._valid) return null;
|
||||
|
||||
const type = this.type;
|
||||
|
||||
const user = this.author || {};
|
||||
const target = this.mentions[0] || {};
|
||||
|
||||
if (type === MessageTypes.RECIPIENT_ADD) {
|
||||
return user.username + " added " + target.username + " to the group.";
|
||||
}
|
||||
|
||||
if (type === MessageTypes.RECIPIENT_REMOVE) {
|
||||
if (user.id !== target.id) {
|
||||
return user.username + " added " + target.username + " to the group.";
|
||||
} else {
|
||||
return user.username + " left the group.";
|
||||
}
|
||||
}
|
||||
|
||||
if (type === MessageTypes.CALL) {
|
||||
const localUserId = this._discordie._user && this._discordie._user.id;
|
||||
const isActive =
|
||||
this._discordie._calls.isActive(this.channel_id, this.id);
|
||||
const isMissed =
|
||||
!isActive &&
|
||||
this.call && this.call.participants &&
|
||||
this.call.participants.indexOf(localUserId) < 0;
|
||||
|
||||
if (isMissed) {
|
||||
return "You missed a call from " + user.username + ".";
|
||||
}
|
||||
|
||||
if (isActive) {
|
||||
return user.username + " started a call. Join the call.";
|
||||
} else {
|
||||
return user.username + " started a call.";
|
||||
}
|
||||
}
|
||||
|
||||
if (type === MessageTypes.CHANNEL_NAME_CHANGE) {
|
||||
return user.username + " changed the channel name: " + this.content;
|
||||
}
|
||||
|
||||
if (type === MessageTypes.CHANNEL_ICON_CHANGE) {
|
||||
return user.username + " changed the channel icon.";
|
||||
}
|
||||
|
||||
if (type === MessageTypes.CHANNEL_PINNED_MESSAGE) {
|
||||
return user.username +
|
||||
" pinned a message to this channel. See all the pins.";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves username that should be displayed with this message.
|
||||
* @return {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get displayUsername() {
|
||||
if (!this._valid) return null;
|
||||
const member = this.member;
|
||||
const author = this.author;
|
||||
const nick = member ? member.nick : null;
|
||||
const username = author ? author.username : null;
|
||||
return nick || username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets channel of this message.
|
||||
*
|
||||
* Returns null if message does not exist in cache.
|
||||
* @returns {ITextChannel|IDirectMessageChannel|null}
|
||||
* @readonly
|
||||
*/
|
||||
get channel() {
|
||||
if (this.isPrivate) {
|
||||
return this._discordie.DirectMessageChannels.get(this.channel_id);
|
||||
}
|
||||
return this._discordie.Channels.get(this.channel_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets guild of this message.
|
||||
*
|
||||
* Returns null if message does not exist in cache or from a private
|
||||
* channel (direct message).
|
||||
* @returns {IGuild|null}
|
||||
* @readonly
|
||||
*/
|
||||
get guild() {
|
||||
if (this.isPrivate || !this.isCached) return null;
|
||||
return this.channel ? this.channel.guild : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets member instance of author.
|
||||
*
|
||||
* Returns null for private channels, if message does not exist in cache,
|
||||
* the author is no longer a member of the guild, or it is a webhook message.
|
||||
* @returns {IGuildMember|null}
|
||||
* @readonly
|
||||
*/
|
||||
get member() {
|
||||
if (this.isPrivate || !this.isCached) return null;
|
||||
return this._discordie.Users.getMember(this.guild.id, this.author.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of all known (cached) versions of this message (including
|
||||
* the latest).
|
||||
* Sorted from latest (first) to oldest (last).
|
||||
* Does not include embeds.
|
||||
* @returns {Array<Object>}
|
||||
* @readonly
|
||||
*/
|
||||
get edits() {
|
||||
return this._discordie._messages.getEdits(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves user and channel references in `content` property to proper names.
|
||||
* References that are not found in cache will be left as is and not resolved.
|
||||
*
|
||||
* Returns null if this message is not cached.
|
||||
* @returns {String|null}
|
||||
* @example
|
||||
* var content = message.content;
|
||||
* // 'just a message for <@157838423632817262> in <#78826383786329613>'
|
||||
* var resolvedContent = message.resolveContent();
|
||||
* // 'just a message for @testie in #general'
|
||||
* var resolvedContent = client.Messages.resolveContent(message.content);
|
||||
* // 'just a message for @testie in #general'
|
||||
*/
|
||||
resolveContent() {
|
||||
if (!this.isCached) return null;
|
||||
return this._discordie.Messages.resolveContent(this.content, this.guild);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to edit this message.
|
||||
*
|
||||
* Editing of other users' messages is not allowed, server will send an
|
||||
* `Error` `Forbidden` and returned promise will be rejected if you attempt
|
||||
* to do so.
|
||||
*
|
||||
* See `IMessageCollection.editMessage` if you are looking for a method
|
||||
* that can operate on JSON or raw message id.
|
||||
* @param {String} [content]
|
||||
* @param {Object} [embed]
|
||||
* Refer to [official API documentation](https://discordapp.com/developers/docs/resources/channel#embed-object)
|
||||
* for embed structure description.
|
||||
* @returns {Promise<IMessage, Error>}
|
||||
*/
|
||||
edit(content, embed) {
|
||||
if (Array.isArray(content)) content = content.join("\n");
|
||||
if (content && typeof content !== "string") content = String(content);
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.channels.patchMessage(this.channel_id, this.id, content, embed)
|
||||
.then(() => rs(this))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete this message.
|
||||
*
|
||||
* See `IMessageCollection.deleteMessage` if you are looking for a method
|
||||
* that can operate on JSON or raw message id.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
delete() {
|
||||
return rest(this._discordie)
|
||||
.channels.deleteMessage(this.channel_id, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to pin this message.
|
||||
*
|
||||
* See `IMessageCollection.pinMessage` if you are looking for a method
|
||||
* that can operate on JSON or raw message id.
|
||||
* @returns {Promise<IMessage, Error>}
|
||||
*/
|
||||
pin() {
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.channels.pinMessage(this.channel_id, this.id)
|
||||
.then(() => rs(this))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to unpin this message.
|
||||
*
|
||||
* See `IMessageCollection.unpinMessage` if you are looking for a method
|
||||
* that can operate on JSON or raw message id.
|
||||
* @returns {Promise<IMessage, Error>}
|
||||
*/
|
||||
unpin() {
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.channels.unpinMessage(this.channel_id, this.id)
|
||||
.then(() => rs(this))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to fetch users who reacted to this message with the
|
||||
* specified emoji.
|
||||
* @param {Object|String} emoji
|
||||
* Partial emoji `{id: String|null, name: String}` or a unicode emoji
|
||||
* @param {Number} [limit] - Max 100 users per fetch
|
||||
* @param {IUser|String} [after] - Start list from specified user id
|
||||
* @return {Promise<Array<IUser>, Error>}
|
||||
*/
|
||||
fetchReactions(emoji, limit, after) {
|
||||
emoji = Utils.emojiToCode(emoji);
|
||||
limit = limit || 100;
|
||||
after = after ? after.valueOf() : after;
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.channels.getReactions(this.channel_id, this.id, emoji, limit, after)
|
||||
.then(users => rs(users.map(user => client.Users.get(user.id))))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to add a reaction to this message with the specified
|
||||
* emoji.
|
||||
* @param {Object|String} emoji
|
||||
* Partial emoji `{id: String|null, name: String}` or a unicode emoji
|
||||
* @return {Promise}
|
||||
* @example
|
||||
* message.addReaction(message.reactions[0].emoji);
|
||||
* message.addReaction("\uD83D\uDE2C");
|
||||
*/
|
||||
addReaction(emoji) {
|
||||
emoji = Utils.emojiToCode(emoji);
|
||||
|
||||
return rest(this._discordie)
|
||||
.channels.addReaction(this.channel_id, this.id, emoji);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to remove a reaction to this message with the specified
|
||||
* emoji.
|
||||
* @param {Object|String} emoji
|
||||
* Partial emoji `{id: String|null, name: String}` or a unicode emoji
|
||||
* @param {IUser|String} [user] - Remove reaction of another user
|
||||
* @return {Promise}
|
||||
*/
|
||||
removeReaction(emoji, user) {
|
||||
emoji = Utils.emojiToCode(emoji);
|
||||
user = user ? user.valueOf() : user;
|
||||
|
||||
return rest(this._discordie)
|
||||
.channels.removeReaction(this.channel_id, this.id, emoji, user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to remove all reactions from this message.
|
||||
* @return {Promise}
|
||||
*/
|
||||
clearReactions() {
|
||||
return rest(this._discordie)
|
||||
.channels.deleteReactions(this.channel_id, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to send a reply to channel the message was from, prefixing
|
||||
* content with author's mention in non-private channels.
|
||||
* @param {String|Array<String>} content
|
||||
* Strings will be sent as is, arrays - joined with a newline character.
|
||||
* @param {IUser|IGuildMember|Array<IUser>|Array<IGuildMember>} [mentions]
|
||||
* Deprecated: left for backward compatibility.
|
||||
* @param {boolean} [tts]
|
||||
* @param {Object} [embed]
|
||||
* Refer to [official API documentation](https://discordapp.com/developers/docs/resources/channel#embed-object)
|
||||
* for embed structure description.
|
||||
* @returns {Promise<IMessage, Error>}
|
||||
*/
|
||||
reply(content, mentions, tts, embed) {
|
||||
if (this.isPrivate) {
|
||||
return this.channel.sendMessage(content, mentions, tts, embed);
|
||||
}
|
||||
return this.channel
|
||||
.sendMessage(`${this.author.mention}, ${content}`, mentions, tts, embed);
|
||||
}
|
||||
}
|
||||
|
||||
IMessage._inherit(Message, function modelPropertyGetter(key) {
|
||||
return this._discordie._messages.get(this._messageId)[key];
|
||||
});
|
||||
IMessage._setSuppressErrors(true);
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IMessage
|
||||
* @name author
|
||||
* @returns {IUser}
|
||||
*/
|
||||
IMessage._setValueOverride("author", function(user) {
|
||||
if (user && this.webhook_id) {
|
||||
const factory = () => new IUser(this._discordie, user.id, user);
|
||||
return this._discordie.Users._getOrCreateInterface(user, factory);
|
||||
}
|
||||
return user ? this._discordie.Users.get(user.id) : null;
|
||||
});
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IMessage
|
||||
* @name mentions
|
||||
* @returns {Array<IUser>}
|
||||
*/
|
||||
IMessage._setValueOverride("mentions", function(v) {
|
||||
return v ? v.map(u => this._discordie.Users.get(u.id)) : [];
|
||||
});
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IMessage
|
||||
* @name mention_roles
|
||||
* @returns {Array<IRole>}
|
||||
*/
|
||||
IMessage._setValueOverride("mention_roles", function(rolesRaw) {
|
||||
if (!rolesRaw || !this.guild) return [];
|
||||
var guildId = this.guild.id;
|
||||
return rolesRaw.map(id => new IRole(this._discordie, id, guildId));
|
||||
});
|
||||
|
||||
module.exports = IMessage;
|
374
node_modules/discordie/lib/interfaces/IMessageCollection.js
generated
vendored
Normal file
374
node_modules/discordie/lib/interfaces/IMessageCollection.js
generated
vendored
Normal file
@ -0,0 +1,374 @@
|
||||
"use strict";
|
||||
|
||||
const ICollectionBase = require("./ICollectionBase");
|
||||
const IMessage = require("./IMessage");
|
||||
const IChannel = require("./IChannel");
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @extends ICollectionBase
|
||||
* @description
|
||||
* Collection with all cached messages.
|
||||
*
|
||||
* **Includes deleted messages** - you can filter them by checking
|
||||
* `IMessage.deleted` boolean.
|
||||
*/
|
||||
class IMessageCollection extends ICollectionBase {
|
||||
constructor(discordie, valuesGetter, valueGetter) {
|
||||
super({
|
||||
valuesGetter: valuesGetter,
|
||||
valueGetter: valueGetter,
|
||||
itemFactory: (id) => new IMessage(this._discordie, id)
|
||||
});
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of cached messages in `channel`, sorted in order of
|
||||
* arrival (message cache is sorted on message insertion, not when this
|
||||
* getter is invoked).
|
||||
*
|
||||
* Returns an empty array if channel no longer exists.
|
||||
*
|
||||
* > **Note:** Message cache also includes deleted messages.
|
||||
* > You can filter them by checking `IMessage.deleted` boolean.
|
||||
* @param {IChannel|String} channel
|
||||
* @returns {Array<IMessage>}
|
||||
*/
|
||||
forChannel(channel) {
|
||||
var cache = this._discordie._messages.getChannelCache(channel.valueOf());
|
||||
if (!cache || !cache.size) return [];
|
||||
return cache.map(message => this._getOrCreateInterface(message));
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges channel cache.
|
||||
* @param {IChannel|String} channel
|
||||
*/
|
||||
purgeChannelCache(channel) {
|
||||
channel = channel.valueOf();
|
||||
return this._discordie._messages.purgeChannelCache(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of cached pinned messages in `channel`.
|
||||
*
|
||||
* Pinned message cache is updated only if all pinned messages have been
|
||||
* loaded with `ITextChannel.fetchPinned()`.
|
||||
*
|
||||
* Returns an empty array if channel no longer exists or if pinned messages
|
||||
* have not been fetched yet.
|
||||
* @param {IChannel|String} channel
|
||||
* @returns {Array<IMessage>}
|
||||
*/
|
||||
forChannelPinned(channel) {
|
||||
var cache = this._discordie._messages.getChannelPinned(channel.valueOf());
|
||||
if (!cache) return [];
|
||||
return cache.map(msg => this._getOrCreateInterface(msg));
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges pinned message cache for `channel`.
|
||||
* @param {IChannel|String} channel
|
||||
*/
|
||||
purgeChannelPinned(channel) {
|
||||
channel = channel.valueOf();
|
||||
return this._discordie._messages.purgeChannelPinned(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges pinned message cache globally.
|
||||
*/
|
||||
purgePinned() {
|
||||
return this._discordie._messages.purgePinned();
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges edits cache globally.
|
||||
*/
|
||||
purgeEdits() {
|
||||
return this._discordie._messages.purgeEdits();
|
||||
}
|
||||
|
||||
/**
|
||||
* Purges message cache globally.
|
||||
*/
|
||||
purgeAllCache() {
|
||||
return this._discordie._messages.purgeAllCache();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets channel message cache limit.
|
||||
* @param {IChannel|String} channel
|
||||
* @returns {Number}
|
||||
*/
|
||||
getChannelMessageLimit(channel) {
|
||||
channel = channel.valueOf();
|
||||
return this._discordie._messages.getChannelMessageLimit(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets channel message cache limit (with a minimum of 1).
|
||||
* Limit reverts to default when channel (or cache) is destroyed.
|
||||
* Returns false if limit is invalid or channel does not exist.
|
||||
* @param {IChannel|String} channel
|
||||
* @param {Number} limit
|
||||
* @returns {Boolean}
|
||||
*/
|
||||
setChannelMessageLimit(channel, limit) {
|
||||
channel = channel.valueOf();
|
||||
return this._discordie._messages.setChannelMessageLimit(channel, limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets global message cache limit per channel.
|
||||
* @returns {Number}
|
||||
*/
|
||||
getMessageLimit() {
|
||||
return this._discordie._messages.getMessageLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets global message cache limit per channel (with a minimum of 1).
|
||||
* Does not affect channels with custom limits if new is lower than current.
|
||||
* @param {Number} limit
|
||||
*/
|
||||
setMessageLimit(limit) {
|
||||
return this._discordie._messages.setMessageLimit(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets global edits cache limit per message.
|
||||
* @returns {Number}
|
||||
*/
|
||||
getEditsLimit() {
|
||||
return this._discordie._messages.getEditsLimit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets global edits cache limit per message.
|
||||
* @param {Number} limit
|
||||
*/
|
||||
setEditsLimit(limit) {
|
||||
return this._discordie._messages.setEditsLimit(limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to edit a message.
|
||||
* Alternative method for editing messages that are not in cache.
|
||||
*
|
||||
* Editing of other users' messages is not allowed, server will send an
|
||||
* `Error` `Forbidden` and returned promise will be rejected if you attempt
|
||||
* to do so.
|
||||
*
|
||||
* Parameter `messageId` can be an object with fields `{channel_id, id}`,
|
||||
* where `id` is a String message id, `channel_id` is a String channel id.
|
||||
*
|
||||
* Parameter `channelId` is ignored when `messageId` is an object or
|
||||
* an instance of `IMessage`.
|
||||
*
|
||||
* Returns a promise that resolves to a JSON object of the edited message.
|
||||
*
|
||||
* @param {String|Object} [content]
|
||||
* @param {IMessage|Object|String} messageId
|
||||
* @param {String} channelId - Ignored if `messageId` is an object with `id`
|
||||
* @param {Object} [embed]
|
||||
* Refer to [official API documentation](https://discordapp.com/developers/docs/resources/channel#embed-object)
|
||||
* for embed structure description.
|
||||
* @returns {Promise<Object, Error>}
|
||||
* @example
|
||||
* var message = client.Messages.find(m => true); // get any message
|
||||
* client.Messages.editMessage("new content", message);
|
||||
*
|
||||
* var jsonMessage = {id: message.id, channel_id: message.channel_id};
|
||||
* client.Messages.editMessage("new content", jsonMessage);
|
||||
*
|
||||
* client.Messages.editMessage("new content", message.id, message.channel_id);
|
||||
*/
|
||||
editMessage(content, messageId, channelId, embed) {
|
||||
if (Array.isArray(content)) content = content.join("\n");
|
||||
if (content && typeof content !== "string") content = String(content);
|
||||
|
||||
var message = {id: messageId, channel_id: channelId};
|
||||
|
||||
if (messageId && messageId.id) {
|
||||
message.id = messageId.id;
|
||||
message.channel_id = messageId.channel_id || messageId.channelId;
|
||||
}
|
||||
|
||||
return rest(this._discordie)
|
||||
.channels.patchMessage(message.channel_id, message.id, content, embed);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete a message.
|
||||
* Alternative method for deleting messages that are not in cache.
|
||||
*
|
||||
* Parameter `messageId` can be an object with fields `{channel_id, id}`,
|
||||
* where `id` is a String message id, `channel_id` is a String channel id.
|
||||
*
|
||||
* Parameter `channelId` is ignored when `messageId` is an object or
|
||||
* an instance of `IMessage`.
|
||||
*
|
||||
* @param {IMessage|Object|String} messageId
|
||||
* @param {String} channelId - Ignored if `messageId` is an object with `id`
|
||||
* @returns {Promise}
|
||||
* @example
|
||||
* var message = client.Messages.find(m => true); // get any message
|
||||
* client.Messages.deleteMessage(message);
|
||||
*
|
||||
* var jsonMessage = {id: message.id, channel_id: message.channel_id};
|
||||
* client.Messages.deleteMessage(jsonMessage);
|
||||
*
|
||||
* client.Messages.deleteMessage(message.id, message.channel_id);
|
||||
*/
|
||||
deleteMessage(messageId, channelId) {
|
||||
var message = {id: messageId, channel_id: channelId};
|
||||
|
||||
if (messageId && messageId.id) {
|
||||
message.id = messageId.id;
|
||||
message.channel_id = messageId.channel_id || messageId.channelId;
|
||||
}
|
||||
|
||||
return rest(this._discordie)
|
||||
.channels.deleteMessage(message.channel_id, message.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to pin a message.
|
||||
* Alternative method for pinning messages that are not in cache.
|
||||
*
|
||||
* Accepts same parameters as `IMessageCollection.deleteMessage`.
|
||||
*
|
||||
* @param {IMessage|Object|String} messageId
|
||||
* @param {String} channelId - Ignored if `messageId` is an object with `id`
|
||||
* @returns {Promise}
|
||||
*/
|
||||
pinMessage(messageId, channelId) {
|
||||
var message = {id: messageId, channel_id: channelId};
|
||||
|
||||
if (messageId && messageId.id) {
|
||||
message.id = messageId.id;
|
||||
message.channel_id = messageId.channel_id || messageId.channelId;
|
||||
}
|
||||
|
||||
return rest(this._discordie)
|
||||
.channels.pinMessage(message.channel_id, message.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to unpin a message.
|
||||
* Alternative method for unpinning messages that are not in cache.
|
||||
*
|
||||
* Accepts same parameters as `IMessageCollection.deleteMessage`.
|
||||
*
|
||||
* @param {IMessage|Object|String} messageId
|
||||
* @param {String} channelId - Ignored if `messageId` is an object with `id`
|
||||
* @returns {Promise}
|
||||
*/
|
||||
unpinMessage(messageId, channelId) {
|
||||
var message = {id: messageId, channel_id: channelId};
|
||||
|
||||
if (messageId && messageId.id) {
|
||||
message.id = messageId.id;
|
||||
message.channel_id = messageId.channel_id || messageId.channelId;
|
||||
}
|
||||
|
||||
return rest(this._discordie)
|
||||
.channels.unpinMessage(message.channel_id, message.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete multiple messages.
|
||||
*
|
||||
* If `messages` array contains instances of `IMessage`, parameter `channel`
|
||||
* is not required as it will be determined from the first message instance.
|
||||
* Also deleted messages will be omitted from the request.
|
||||
*
|
||||
* If `messages` array is empty, returned promise resolves instantly
|
||||
* without sending a request.
|
||||
* @param {Array<IMessage|String>} messages
|
||||
* @param {IChannel|String} [channel]
|
||||
* Channel or channel id, required is `messages` is an array of string ids
|
||||
* @returns {Promise}
|
||||
*/
|
||||
deleteMessages(messages, channel) {
|
||||
if (!Array.isArray(messages))
|
||||
throw new TypeError("Param 'messages' must be an array");
|
||||
|
||||
messages = messages.filter(m => {
|
||||
if (m instanceof IMessage)
|
||||
return !m.deleted;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (!messages.length) return Promise.resolve();
|
||||
|
||||
var internalMessage = messages.find(v => v.channel_id);
|
||||
if (!internalMessage && !channel)
|
||||
throw new TypeError("Param 'channel' must be defined for arrays of ids");
|
||||
|
||||
channel = (internalMessage && !channel) ?
|
||||
internalMessage.channel_id :
|
||||
channel.valueOf();
|
||||
|
||||
// bulk-delete returns 'Bad Request' in this case
|
||||
if (messages.length === 1) {
|
||||
return rest(this._discordie)
|
||||
.channels.deleteMessage(channel, messages[0].valueOf());
|
||||
}
|
||||
|
||||
return rest(this._discordie)
|
||||
.channels.deleteMessages(channel, messages.map(v => v.valueOf()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves user and channel references to proper names.
|
||||
* References that are not found in cache will be left as is and not resolved.
|
||||
* @param {String} content
|
||||
* @param {IGuild|String} [guild]
|
||||
* Optional guild to resolve roles and nicknames from
|
||||
* @returns {String}
|
||||
* @example
|
||||
* var content = message.content;
|
||||
* // 'just a message for <@157838423632817262> in <#78826383786329613>'
|
||||
* var resolvedContent = message.resolveContent();
|
||||
* // 'just a message for @testie in #general'
|
||||
* var resolvedContent = client.Messages.resolveContent(message.content);
|
||||
* // 'just a message for @testie in #general'
|
||||
*/
|
||||
resolveContent(content, guild) {
|
||||
if (typeof content !== "string")
|
||||
throw new TypeError("Param 'content' is not a string");
|
||||
if (guild) {
|
||||
var guildId = guild.valueOf();
|
||||
guild = this._discordie.Guilds.get(guildId);
|
||||
}
|
||||
return content.replace(/<(@!?|#|@&)([0-9]+)>/g, (match, type, id) => {
|
||||
if (type === "@" || type === "@!") { // user
|
||||
var user = this._discordie.Users.get(id);
|
||||
if (!user) return match;
|
||||
if (guild && type === "@!") {
|
||||
var member = user.memberOf(guild);
|
||||
return (member && ("@" + member.name)) || match;
|
||||
}
|
||||
return (user && ("@" + user.username)) || match;
|
||||
}
|
||||
else if (type === "#") { // channel
|
||||
var channel = this._discordie.Channels.get(id);
|
||||
return (channel && ("#" + channel.name)) || match;
|
||||
}
|
||||
else if (type === "@&") { // role
|
||||
if (!guild || !guild.roles) return match;
|
||||
var role = guild.roles.find(r => r.id === id);
|
||||
return (role && ("@" + role.name)) || match;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IMessageCollection;
|
121
node_modules/discordie/lib/interfaces/IPermissionOverwrite.js
generated
vendored
Normal file
121
node_modules/discordie/lib/interfaces/IPermissionOverwrite.js
generated
vendored
Normal file
@ -0,0 +1,121 @@
|
||||
"use strict";
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const IPermissions = require("./IPermissions");
|
||||
const Utils = require("../core/Utils");
|
||||
const PermissionOverwrite = require("../models/PermissionOverwrite");
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const ChannelTypes = Constants.ChannelTypes;
|
||||
const PermissionSpecs = Constants.PermissionSpecs;
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model PermissionOverwrite
|
||||
* @extends IBase
|
||||
*/
|
||||
class IPermissionOverwrite extends IBase {
|
||||
constructor(discordie, overwriteId, channelId) {
|
||||
super();
|
||||
this._discordie = discordie;
|
||||
this._overwriteId = overwriteId;
|
||||
this._channelId = channelId;
|
||||
|
||||
const channel = discordie._channels.get(channelId) || {};
|
||||
|
||||
const spec = (channel.type == ChannelTypes.GUILD_VOICE ?
|
||||
PermissionSpecs.VoiceChannel :
|
||||
PermissionSpecs.TextChannel
|
||||
);
|
||||
this._allow = new IPermissions(this.getRaw().allow, spec);
|
||||
this._deny = new IPermissions(this.getRaw().deny, spec);
|
||||
|
||||
Utils.privatify(this);
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets date and time the member or role of this overwrite was created at.
|
||||
* @returns {Date}
|
||||
* @readonly
|
||||
* @ignore
|
||||
*/
|
||||
get createdAt() {
|
||||
return new Date(Utils.timestampFromSnowflake(this.id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads original permissions from cache and updates this object.
|
||||
*/
|
||||
reload() {
|
||||
const raw = this.getRaw();
|
||||
if (!raw) return;
|
||||
this._allow.raw = raw.allow;
|
||||
this._deny.raw = raw.deny;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to commit changes made to this permission overwrite object.
|
||||
* @returns {Promise<IPermissionOverwrite, Error>}
|
||||
*/
|
||||
commit() {
|
||||
return new Promise((rs, rj) => {
|
||||
const raw = this.getRaw();
|
||||
raw.allow = this._allow.raw;
|
||||
raw.deny = this._deny.raw;
|
||||
|
||||
rest(this._discordie)
|
||||
.channels.putPermissionOverwrite(this._channelId, raw)
|
||||
.then(() => rs(this))
|
||||
.catch(e => {
|
||||
this.reload();
|
||||
return rj(e);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete this permission overwrite.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
delete() {
|
||||
return rest(this._discordie)
|
||||
.channels.deletePermissionOverwrite(this._channelId, this.id);
|
||||
}
|
||||
}
|
||||
|
||||
IPermissionOverwrite._inherit(PermissionOverwrite, function(key) {
|
||||
const channel = this._discordie._channels.get(this._channelId);
|
||||
if (!channel) return null;
|
||||
const overwrite = channel.permission_overwrites
|
||||
.find(o => o.id == this._overwriteId);
|
||||
if (!overwrite) return null;
|
||||
return overwrite[key];
|
||||
});
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IPermissionOverwrite
|
||||
* @name allow
|
||||
* @returns {IPermissions}
|
||||
*/
|
||||
IPermissionOverwrite._setValueOverride("allow", function(v) {
|
||||
return this._allow;
|
||||
});
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IPermissionOverwrite
|
||||
* @name deny
|
||||
* @returns {IPermissions}
|
||||
*/
|
||||
IPermissionOverwrite._setValueOverride("deny", function(v) {
|
||||
return this._deny;
|
||||
});
|
||||
|
||||
module.exports = IPermissionOverwrite;
|
202
node_modules/discordie/lib/interfaces/IPermissions.js
generated
vendored
Normal file
202
node_modules/discordie/lib/interfaces/IPermissions.js
generated
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Permissions = Constants.Permissions;
|
||||
const PermissionsDefault = Constants.PermissionsDefault;
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @description
|
||||
* Wrapper for numeric permission values.
|
||||
*
|
||||
* Contains boolean getters/setters (different for roles and channels).
|
||||
*
|
||||
* - `.Text` section only exists for text channels;
|
||||
* - `.Voice` section only exists for voice channels;
|
||||
* - `.General` section exists for both;
|
||||
* - Roles contain all properties - both `.Text` and `.Voice` sections.
|
||||
*
|
||||
* Example of role permission properties:
|
||||
* ```
|
||||
* General: {
|
||||
* CREATE_INSTANT_INVITE,
|
||||
* KICK_MEMBERS,
|
||||
* BAN_MEMBERS,
|
||||
* ADMINISTRATOR,
|
||||
* MANAGE_CHANNELS,
|
||||
* MANAGE_GUILD,
|
||||
* CHANGE_NICKNAME,
|
||||
* MANAGE_NICKNAMES,
|
||||
* MANAGE_ROLES,
|
||||
* MANAGE_WEBHOOKS,
|
||||
* MANAGE_EMOJIS,
|
||||
* },
|
||||
* Text: {
|
||||
* READ_MESSAGES,
|
||||
* SEND_MESSAGES,
|
||||
* SEND_TTS_MESSAGES,
|
||||
* MANAGE_MESSAGES,
|
||||
* EMBED_LINKS,
|
||||
* ATTACH_FILES,
|
||||
* READ_MESSAGE_HISTORY,
|
||||
* MENTION_EVERYONE,
|
||||
* EXTERNAL_EMOTES,
|
||||
* ADD_REACTIONS,
|
||||
* },
|
||||
* Voice: {
|
||||
* CONNECT,
|
||||
* SPEAK,
|
||||
* MUTE_MEMBERS,
|
||||
* DEAFEN_MEMBERS,
|
||||
* MOVE_MEMBERS,
|
||||
* USE_VAD,
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Example of text channel permission properties:
|
||||
* ```
|
||||
* General: {
|
||||
* CREATE_INSTANT_INVITE,
|
||||
* MANAGE_CHANNEL,
|
||||
* MANAGE_PERMISSIONS
|
||||
* },
|
||||
* Text: {
|
||||
* READ_MESSAGES,
|
||||
* SEND_MESSAGES,
|
||||
* SEND_TTS_MESSAGES,
|
||||
* MANAGE_MESSAGES,
|
||||
* EMBED_LINKS,
|
||||
* ATTACH_FILES,
|
||||
* READ_MESSAGE_HISTORY,
|
||||
* MENTION_EVERYONE,
|
||||
* EXTERNAL_EMOTES,
|
||||
* ADD_REACTIONS,
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* @example
|
||||
* var guild = client.Guilds.find(g => g.name == "test");
|
||||
* guild.createRole().then(role => {
|
||||
* var perms = role.permissions;
|
||||
* perms.General.KICK_MEMBERS = true;
|
||||
* perms.General.BAN_MEMBERS = true;
|
||||
* perms.Text.MENTION_EVERYONE = true;
|
||||
*
|
||||
* var newRoleName = "Testing";
|
||||
* var color = 0xE74C3C; // red
|
||||
* var hoist = true; // display as separate group
|
||||
*
|
||||
* role.commit(newRoleName, color, hoist);
|
||||
* }).catch(err => console.log("Failed to create role:", err));
|
||||
*/
|
||||
class IPermissions {
|
||||
constructor(raw, permissionSpec) {
|
||||
this.raw = raw || 0;
|
||||
for (let type in permissionSpec) {
|
||||
this[type] = {};
|
||||
for (let permission in permissionSpec[type]) {
|
||||
const bit = permissionSpec[type][permission];
|
||||
Object.defineProperty(this[type], permission, {
|
||||
enumerable: true,
|
||||
get: () => (this.raw & bit) === bit,
|
||||
set: (v) => v ? (this.raw |= bit) : (this.raw &= ~bit)
|
||||
});
|
||||
}
|
||||
Object.seal(this[type]);
|
||||
}
|
||||
Object.seal(this);
|
||||
}
|
||||
|
||||
inspect() { return JSON.parse(JSON.stringify(this)); }
|
||||
|
||||
setAll() { this.raw = IPermissions.ALL; }
|
||||
unsetAll() { this.raw = IPermissions.NONE; }
|
||||
|
||||
static get ALL() { return (~0 >>> 0); }
|
||||
static get DEFAULT() { return PermissionsDefault; }
|
||||
static get NONE() { return 0; }
|
||||
|
||||
static resolveRaw(user, context) {
|
||||
// referencing here to avoid circular require()
|
||||
const IUser = require("./IUser");
|
||||
const IAuthenticatedUser = require("./IAuthenticatedUser");
|
||||
const IChannel = require("./IChannel");
|
||||
const IGuild = require("./IGuild");
|
||||
const IGuildMember = require("./IGuildMember");
|
||||
|
||||
if (!(user instanceof IUser) && !(user instanceof IAuthenticatedUser))
|
||||
throw new TypeError("user must be an instance of IUser");
|
||||
if (!(context instanceof IChannel) && !(context instanceof IGuild))
|
||||
throw new TypeError("context must be an instance of IChannel or IGuild");
|
||||
|
||||
if (!context._valid) throw new Error("Invalid context");
|
||||
|
||||
let overwrites = null;
|
||||
if (context instanceof IChannel) {
|
||||
overwrites = context.getRaw().permission_overwrites;
|
||||
context = context.guild;
|
||||
}
|
||||
|
||||
if (context.isOwner(user))
|
||||
return IPermissions.ALL;
|
||||
|
||||
const member = user instanceof IGuildMember ?
|
||||
user : context._discordie.Users.getMember(context.id, user.id);
|
||||
|
||||
if (!member) throw new Error("User is not a member of the context");
|
||||
|
||||
const contextRaw = context.getRaw();
|
||||
const roleEveryone = contextRaw ? contextRaw.roles.get(context.id) : null;
|
||||
|
||||
// apply default permissions
|
||||
let permissions = roleEveryone ?
|
||||
roleEveryone.permissions : IPermissions.DEFAULT;
|
||||
|
||||
// then roles assigned for member
|
||||
const memberRoles = member ? member.roles : null;
|
||||
if (memberRoles) {
|
||||
permissions = memberRoles.reduce(
|
||||
(ps, role) => ps | role.permissions.raw,
|
||||
permissions
|
||||
);
|
||||
}
|
||||
|
||||
if (permissions & Permissions.General.ADMINISTRATOR)
|
||||
return IPermissions.ALL;
|
||||
|
||||
if (overwrites) {
|
||||
const applyOverwrite = (overwrite) => {
|
||||
if (!overwrite) return;
|
||||
permissions &= ~overwrite.deny;
|
||||
permissions |= overwrite.allow;
|
||||
};
|
||||
|
||||
// then channel specific @everyone role
|
||||
const overwriteEveryone = overwrites.find(o => o.id == context.id);
|
||||
applyOverwrite(overwriteEveryone);
|
||||
|
||||
if (member) {
|
||||
// then member roles for channel
|
||||
if (memberRoles)
|
||||
memberRoles.forEach(role =>
|
||||
applyOverwrite(overwrites.find(o => o.id == role.id))
|
||||
);
|
||||
|
||||
// then member specific permissions for channel
|
||||
const overwriteMember = overwrites.find(o => o.id == member.id);
|
||||
applyOverwrite(overwriteMember);
|
||||
}
|
||||
}
|
||||
|
||||
return permissions;
|
||||
}
|
||||
|
||||
static resolve(user, context) {
|
||||
return new IPermissions(
|
||||
IPermissions.resolveRaw(user, context),
|
||||
Permissions
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IPermissions;
|
132
node_modules/discordie/lib/interfaces/IRole.js
generated
vendored
Normal file
132
node_modules/discordie/lib/interfaces/IRole.js
generated
vendored
Normal file
@ -0,0 +1,132 @@
|
||||
"use strict";
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const IPermissions = require("./IPermissions");
|
||||
const Utils = require("../core/Utils");
|
||||
const Role = require("../models/Role");
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const PermissionSpecs = Constants.PermissionSpecs;
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @extends IBase
|
||||
* @model Role
|
||||
*/
|
||||
class IRole extends IBase {
|
||||
constructor(discordie, roleId, guildId) {
|
||||
super();
|
||||
Utils.definePrivate(this, {
|
||||
_discordie: discordie,
|
||||
_roleId: roleId,
|
||||
_guildId: guildId
|
||||
});
|
||||
Utils.definePrivate(this, {
|
||||
_permissions: new IPermissions(
|
||||
this.getRaw("permissions"),
|
||||
PermissionSpecs.Role
|
||||
)
|
||||
});
|
||||
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mention from this role's id.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
* @example
|
||||
* channel.sendMessage(role.mention + ", example mention");
|
||||
*/
|
||||
get mention() {
|
||||
return `<@&${this.id}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads original permissions from cache and updates this object.
|
||||
*/
|
||||
reload() {
|
||||
const rawPermissions = this.getRaw("permissions");
|
||||
if (!rawPermissions) return;
|
||||
this._permissions.raw = rawPermissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to commit changes made to this role object.
|
||||
* @param {String} [name]
|
||||
* @param {Number} [color] - RGB color number
|
||||
* @param {boolean} [hoist] - true if role should be displayed separately
|
||||
* @param {boolean} [mentionable]
|
||||
* @returns {Promise}
|
||||
*/
|
||||
commit(name, color, hoist, mentionable) {
|
||||
const everyone = (this.id == this._guildId);
|
||||
if (!name || everyone) name = this.name;
|
||||
if (hoist === undefined || hoist === null || everyone) hoist = this.hoist;
|
||||
if (color === undefined || color === null || everyone) color = this.color;
|
||||
if (mentionable === undefined || mentionable === null || everyone) {
|
||||
mentionable = this.mentionable;
|
||||
}
|
||||
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).guilds.roles.patchRole(
|
||||
this._guildId, this.id,
|
||||
name, this.permissions.raw, color, hoist, mentionable
|
||||
)
|
||||
.then(() => rs(this))
|
||||
.catch(err => {
|
||||
this.reload();
|
||||
return rj(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves this role to `position` and makes a batch role update request.
|
||||
* @param {Number} position
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setPosition(position) {
|
||||
const guild = this._discordie.Guilds.get(this._guildId);
|
||||
if (!guild) return Promise.reject(new Error("Guild does not exist"));
|
||||
|
||||
// maybe todo: disallow assigning position 0 (role @everyone)
|
||||
const changes = Utils.reorderObjects(guild.roles, this, position);
|
||||
if (!changes) return Promise.resolve();
|
||||
|
||||
return rest(this._discordie)
|
||||
.guilds.roles.batchPatchRoles(this._guildId, changes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete this role.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
delete() {
|
||||
return rest(this._discordie)
|
||||
.guilds.roles.deleteRole(this._guildId, this.id);
|
||||
}
|
||||
}
|
||||
|
||||
IRole._inherit(Role, function modelPropertyGetter(key) {
|
||||
const guild = this._discordie._guilds.get(this._guildId);
|
||||
if (!guild) return null;
|
||||
const role = guild.roles.get(this._roleId);
|
||||
if (!role) return null;
|
||||
return role[key];
|
||||
});
|
||||
|
||||
/**
|
||||
* @readonly
|
||||
* @instance
|
||||
* @memberOf IRole
|
||||
* @name permissions
|
||||
* @returns {IPermissions}
|
||||
*/
|
||||
IRole._setValueOverride("permissions", function(v) {
|
||||
return this._permissions;
|
||||
});
|
||||
|
||||
module.exports = IRole;
|
283
node_modules/discordie/lib/interfaces/ITextChannel.js
generated
vendored
Normal file
283
node_modules/discordie/lib/interfaces/ITextChannel.js
generated
vendored
Normal file
@ -0,0 +1,283 @@
|
||||
"use strict";
|
||||
|
||||
const Utils = require("../core/Utils");
|
||||
const User = require("../models/User");
|
||||
const IChannel = require("./IChannel");
|
||||
const IUser = require("./IUser");
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const Permissions = Constants.Permissions;
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model Channel
|
||||
* @extends IChannel
|
||||
*/
|
||||
class ITextChannel extends IChannel {
|
||||
constructor(discordie, channelId) {
|
||||
super(discordie, channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mention from this channel's id.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
* @example
|
||||
* channel.sendMessage(channel.mention + ", example mention");
|
||||
*/
|
||||
get mention() {
|
||||
return `<#${this.id}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of IGuildMember that
|
||||
* have permissions to read this channel.
|
||||
* @returns {Array<IGuildMember>}
|
||||
* @readonly
|
||||
*/
|
||||
get members() {
|
||||
return this._discordie.Users.membersForChannel(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether it is a default (general) channel.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get isDefaultChannel() {
|
||||
return this.guild_id === this.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether all messages were loaded.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get allMessagesLoaded() {
|
||||
return !this._discordie._messages.channelHasMore(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of cached messages in this channel, sorted in order of
|
||||
* arrival (message cache is sorted on message insertion, not when this
|
||||
* getter is invoked).
|
||||
*
|
||||
* Returns an empty array if channel no longer exists.
|
||||
*
|
||||
* > **Note:** Message cache also includes deleted messages.
|
||||
* > You can filter them by checking `IMessage.deleted` boolean.
|
||||
* @returns {Array<IMessage>}
|
||||
* @readonly
|
||||
*/
|
||||
get messages() {
|
||||
return this._discordie.Messages.forChannel(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to fetch messages for this channel.
|
||||
*
|
||||
* Discord API does not allow fetching more than 100 messages at once.
|
||||
*
|
||||
* Promise resolves with an Object with following structure:
|
||||
* ```js
|
||||
* {
|
||||
* messages: Array<IMessage>,
|
||||
* limit: Number, // same as parameter passed or default value
|
||||
* before: String | null, // message id
|
||||
* after: String | null // message id
|
||||
* }
|
||||
* ```
|
||||
* @param {Number|null} [limit] - Default is 100
|
||||
* @param {IMessage|String|null} [before] - Message or message id
|
||||
* @param {IMessage|String|null} [after] - Message or message id
|
||||
* @returns {Promise<Object, Error>}
|
||||
* @example
|
||||
* var guild = client.Guilds.find(g => g.name == "test");
|
||||
* var channel = guild.generalChannel;
|
||||
*
|
||||
* // simple fetch:
|
||||
* channel.fetchMessages().then(() => {
|
||||
* console.log("[simple] messages in cache: " + channel.messages.length);
|
||||
* });
|
||||
*
|
||||
* // fetching more than 100 messages into cache sequentially:
|
||||
* fetchMessagesEx(channel, 420).then(() => {
|
||||
* console.log("[extended] messages in cache: " + channel.messages.length);
|
||||
* });
|
||||
*
|
||||
* // fetch more messages just like Discord client does
|
||||
* function fetchMessagesEx(channel, left) {
|
||||
* // message cache is sorted on insertion
|
||||
* // channel.messages[0] will get oldest message
|
||||
* var before = channel.messages[0];
|
||||
* return channel.fetchMessages(Math.min(left, 100), before)
|
||||
* .then(e => onFetch(e, channel, left));
|
||||
* }
|
||||
* function onFetch(e, channel, left) {
|
||||
* if (!e.messages.length) return Promise.resolve();
|
||||
* left -= e.messages.length;
|
||||
* console.log(`Received ${e.messages.length}, left: ${left}`);
|
||||
* if (left <= 0) return Promise.resolve();
|
||||
* return fetchMessagesEx(channel, left);
|
||||
* }
|
||||
*/
|
||||
fetchMessages(limit, before, after) {
|
||||
if (!limit) limit = 100;
|
||||
if (before) before = before.valueOf();
|
||||
if (after) after = after.valueOf();
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).channels.getMessages(this.id, limit, before, after)
|
||||
.then(e => {
|
||||
e.messages = e.messages
|
||||
.map(msg => this._discordie.Messages.get(msg.id));
|
||||
return rs(e);
|
||||
})
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of cached pinned messages in this channel.
|
||||
*
|
||||
* Pinned message cache is updated only if all pinned messages have been
|
||||
* loaded with `ITextChannel.fetchPinned()`.
|
||||
*
|
||||
* Returns an empty array if channel no longer exists or if pinned messages
|
||||
* have not been fetched yet.
|
||||
* @returns {Array<IMessage>}
|
||||
* @readonly
|
||||
*/
|
||||
get pinnedMessages() {
|
||||
return this._discordie.Messages.forChannelPinned(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to fetch pinned messages for this channel.
|
||||
*
|
||||
* Promise resolves with an Object with following structure:
|
||||
* ```js
|
||||
* {
|
||||
* channelId: String,
|
||||
* messages: Array<IMessage>
|
||||
* }
|
||||
* ```
|
||||
* @returns {Promise<Object, Error>}
|
||||
*/
|
||||
fetchPinned() {
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie).channels.getPinnedMessages(this.id)
|
||||
.then(e => {
|
||||
e.messages = e.messages
|
||||
.map(msg => this._discordie.Messages.get(msg.id));
|
||||
return rs(e);
|
||||
})
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to send a message to this channel. Messages over 2000
|
||||
* characters will be rejected by the server.
|
||||
*
|
||||
* Use `uploadFile` if you want to send a message with an attachment.
|
||||
* @param {String|Array<String>} content
|
||||
* Strings will be sent as is, arrays - joined with a newline character.
|
||||
* @param {IUser|IGuildMember|Array<IUser>|Array<IGuildMember>} [mentions]
|
||||
* Deprecated: left for backward compatibility.
|
||||
* @param {boolean} [tts]
|
||||
* @param {Object} [embed]
|
||||
* Refer to [official API documentation](https://discordapp.com/developers/docs/resources/channel#embed-object)
|
||||
* for embed structure description.
|
||||
* @returns {Promise<IMessage, Error>}
|
||||
* @example
|
||||
* var guild = client.Guilds.find(g => g.name == "test");
|
||||
* if (!guild) return console.log("invalid guild");
|
||||
*
|
||||
* var channel = guild.generalChannel;
|
||||
*
|
||||
* channel.sendMessage("regular message");
|
||||
* channel.sendMessage("test with tts", true);
|
||||
*
|
||||
* var user = client.Users.find(u => u.username == "test");
|
||||
* if (!user) return console.log("invalid user");
|
||||
*
|
||||
* channel.sendMessage("mentioning user " + user.mention);
|
||||
* channel.sendMessage("@everyone or @here mention if you have permissions");
|
||||
*
|
||||
* channel.sendMessage("message with an embed", false, {
|
||||
* color: 0x3498db,
|
||||
* author: {name: "author name"},
|
||||
* title: "This is an embed",
|
||||
* url: "http://google.com",
|
||||
* timestamp: "2016-11-13T03:43:32.127Z",
|
||||
* fields: [{name: "some field", value: "some value"}],
|
||||
* footer: {text: "footer text"}
|
||||
* });
|
||||
*/
|
||||
sendMessage(content, mentions, tts, embed) {
|
||||
if (Array.isArray(content)) content = content.join("\n");
|
||||
if (typeof content !== "string") content = String(content);
|
||||
|
||||
if (!Array.isArray(mentions)) {
|
||||
embed = tts;
|
||||
tts = mentions;
|
||||
mentions = [];
|
||||
}
|
||||
mentions = Utils.convertMentions(mentions);
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.channels.createMessage(this.id, content, mentions, tts, embed)
|
||||
.then(msg => rs(this._discordie.Messages.get(msg.id)))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to send typing status for this channel.
|
||||
*
|
||||
* Discord client displays it for 10 seconds, sends every 5 seconds.
|
||||
* Stops showing typing status if receives a message from the user.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
sendTyping() {
|
||||
return rest(this._discordie).channels.postTyping(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to upload data to this channel.
|
||||
* Images require a `filename` with a valid extension to actually be uploaded.
|
||||
* @param {Buffer|ReadableStream|String} readableStream
|
||||
* Data to upload or filename as a string
|
||||
* @param {String} filename
|
||||
* Actual filename to show, required for non-string `readableStream`
|
||||
* @param {String} [content] - Additional comment message for attachment
|
||||
* @param {boolean} [tts]
|
||||
* @returns {Promise<IMessage, Error>}
|
||||
* @example
|
||||
* channel.uploadFile(fs.readFileSync("test.png"), "test.png"); // Buffer
|
||||
* channel.uploadFile(fs.createReadStream("test.png"), "test.png"); // Stream
|
||||
* channel.uploadFile("test.png"); // File
|
||||
* channel.uploadFile("test.png", null, "file with message");
|
||||
* channel.uploadFile("test.png", null, "file with message and tts", true);
|
||||
*/
|
||||
uploadFile(readableStream, filename, content, mentions, tts) {
|
||||
if (mentions === true) {
|
||||
tts = mentions;
|
||||
mentions = [];
|
||||
}
|
||||
mentions = Utils.convertMentions(mentions);
|
||||
return new Promise((rs, rj) => {
|
||||
rest(this._discordie)
|
||||
.channels.uploadFile(
|
||||
this.id, readableStream, filename,
|
||||
content, mentions, tts
|
||||
)
|
||||
.then(msg => rs(this._discordie.Messages.get(msg.id)))
|
||||
.catch(rj);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ITextChannel;
|
285
node_modules/discordie/lib/interfaces/IUser.js
generated
vendored
Normal file
285
node_modules/discordie/lib/interfaces/IUser.js
generated
vendored
Normal file
@ -0,0 +1,285 @@
|
||||
"use strict";
|
||||
|
||||
const IBase = require("./IBase");
|
||||
const IPermissions = require("./IPermissions");
|
||||
const Utils = require("../core/Utils");
|
||||
const User = require("../models/User");
|
||||
const Constants = require("../Constants");
|
||||
const Endpoints = Constants.Endpoints;
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model User
|
||||
* @extends IBase
|
||||
* @description
|
||||
* Object representing a user, user-bot, or a webhook-bot.
|
||||
*
|
||||
* Both bots have the `bot` property set to true.
|
||||
*
|
||||
* Each webhook-bot object is unique to a message and may have different
|
||||
* username and avatar, the user collection only contains last seen data.
|
||||
* Use `IMessage.author` to get a message-specific object.
|
||||
*/
|
||||
class IUser extends IBase {
|
||||
constructor(discordie, userId, webhookUser) {
|
||||
super();
|
||||
Utils.definePrivate(this, {
|
||||
_discordie: discordie,
|
||||
_userId: userId,
|
||||
_webhookUser: webhookUser
|
||||
});
|
||||
|
||||
if (this.constructor == IUser) {
|
||||
Object.freeze(this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets date and time the account was registered (created) at.
|
||||
* @returns {Date}
|
||||
* @readonly
|
||||
*/
|
||||
get registeredAt() {
|
||||
return new Date(Utils.timestampFromSnowflake(this.id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets current JPG or GIF avatar URL.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get avatarURL() {
|
||||
const avatar = this.avatar;
|
||||
if (!avatar) return null;
|
||||
|
||||
var fmt = "jpg";
|
||||
if (avatar.length >= 2 && avatar[0] === "a" && avatar[1] === "_") {
|
||||
fmt = "gif";
|
||||
}
|
||||
|
||||
return Constants.CDN_ENDPOINT + Endpoints.CDN_AVATAR(this.id, avatar, fmt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets current JPG avatar URL.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get staticAvatarURL() {
|
||||
const avatar = this.avatar;
|
||||
if (!avatar) return null;
|
||||
return Constants.CDN_ENDPOINT + Endpoints.CDN_AVATAR(this.id, avatar);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current status of the user.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
*/
|
||||
get status() {
|
||||
return this._discordie._presences.getStatus(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current game the user is playing.
|
||||
* @returns {Object|null}
|
||||
* @readonly
|
||||
*/
|
||||
get game() {
|
||||
return this._discordie._presences.getGame(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the current game the user is playing.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get gameName() {
|
||||
return this.game ? this.game.name : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Previous status of the user.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
*/
|
||||
get previousStatus() {
|
||||
return this._discordie._presences.getPreviousStatus(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Previous game the user was playing.
|
||||
* @returns {Object|null}
|
||||
* @readonly
|
||||
*/
|
||||
get previousGame() {
|
||||
return this._discordie._presences.getPreviousGame(this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the previous game the user was playing.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get previousGameName() {
|
||||
return this.previousGame ? this.previousGame.name : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks whether the user is mentioned in a `message`.
|
||||
* @param {IMessage} message
|
||||
* @param {boolean} ignoreImplicitMentions
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isMentioned(message, ignoreImplicitMentions) {
|
||||
const IMessage = require("./IMessage");
|
||||
|
||||
if (!message) return false;
|
||||
if (!(message instanceof IMessage)) {
|
||||
if (message.id) message = message.id;
|
||||
message = this._discordie.Messages.get(message);
|
||||
if (!message) return false;
|
||||
}
|
||||
|
||||
return message.mentions.some(mention => mention.id === this.id) ||
|
||||
(ignoreImplicitMentions === true ? false : message.mention_everyone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens or gets existing Direct Message channel.
|
||||
* @returns {Promise<IDirectMessageChannel, Error>}
|
||||
*/
|
||||
openDM() {
|
||||
return this._discordie.DirectMessageChannels.getOrOpen(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to get a guild member interface, returns null if this user is not
|
||||
* a member of the `guild` or `guild` is not in cache.
|
||||
* @param {IGuild|String} guild
|
||||
* @returns {IGuildMember|null}
|
||||
*/
|
||||
memberOf(guild) {
|
||||
return this._discordie.Users.getMember(guild.valueOf(), this.id) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves permissions for user in `context`.
|
||||
*
|
||||
* Returns a helper object with getter boolean properties.
|
||||
*
|
||||
* Throws:
|
||||
*
|
||||
* - ** `"user must be an instance of IUser"` **
|
||||
*
|
||||
* If the method was called without binding to a `IUser` object
|
||||
* (as a function).
|
||||
*
|
||||
* - ** `"context must be an instance of IChannel or IGuild"` **
|
||||
*
|
||||
* If context type is invalid.
|
||||
*
|
||||
* - ** `"Invalid context"` **
|
||||
*
|
||||
* If context object no longer exists in cache.
|
||||
*
|
||||
* - ** `"User is not a member of the context"` **
|
||||
*
|
||||
* If this user is not a member of the guild or
|
||||
* guild the channel belongs to.
|
||||
*
|
||||
* See documentation of `IPermissions` for list of possible permissions.
|
||||
* @param {IChannel|IGuild} context
|
||||
* @returns {IPermissions}
|
||||
* @example
|
||||
* const guild = client.Guilds.find(g => g.name == "test");
|
||||
* const channel = guild.channels.find(c => c.name == "restricted");
|
||||
* const user = guild.members.find(m => m.username == "testuser");
|
||||
*
|
||||
* const guildPerms = user.permissionsFor(guild); // resolves to role permissions
|
||||
* const channelPerms = user.permissionsFor(channel); // resolves to channel permissions
|
||||
*
|
||||
* console.log(guildPerms.General.MANAGE_ROLES); // false
|
||||
* console.log(guildPerms.Text.READ_MESSAGES); // true
|
||||
|
||||
* // The `restricted` channel has `READ_MESSAGES` denied
|
||||
* console.log(channelPerms.Text.READ_MESSAGES); // false
|
||||
*/
|
||||
permissionsFor(context) {
|
||||
return IPermissions.resolve(this, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves permissions for user in `context` and checks if
|
||||
* user has `permission`.
|
||||
*
|
||||
* See `IUser.permissionsFor` method for list of throwable errors.
|
||||
*
|
||||
* See documentation of `IPermissions` for full list of possible permissions.
|
||||
* @param {Number} permission - One or multiple permission bits
|
||||
* @param {IChannel|IGuild} context
|
||||
* @returns {boolean}
|
||||
* @example
|
||||
* const guild = client.Guilds.find(g => g.name == "test");
|
||||
* const channel = guild.channels.find(c => c.name == "node_discordie");
|
||||
* const user = guild.members.find(m => m.username == "testuser");
|
||||
* user.can(Discordie.Permissions.General.KICK_MEMBERS, guild); // resolves to role permissions
|
||||
* user.can(Discordie.Permissions.Text.READ_MESSAGES, channel); // resolves to channel permissions
|
||||
*/
|
||||
can(permission, context) {
|
||||
return (IPermissions.resolveRaw(this, context) & permission) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the first voice channel that member of `guild` currently in.
|
||||
* @param {IGuild|String|null} guild
|
||||
* Guild or an id string, null for private call
|
||||
* (call channel is only available if recipient is in call with current user)
|
||||
* @returns {IVoiceChannel|null}
|
||||
*/
|
||||
getVoiceChannel(guild) {
|
||||
const state = this._discordie._voicestates.getUserStateInGuild(
|
||||
(guild ? guild.valueOf() : null), this.id
|
||||
);
|
||||
if (!state) return null;
|
||||
return this._discordie.Channels.get(state.channel_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a mention from this user's id.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
* @example
|
||||
* channel.sendMessage(user.mention + ", example mention");
|
||||
*/
|
||||
get mention() {
|
||||
return `<@${this.id}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a nickname mention from this user's id.
|
||||
* @returns {String}
|
||||
* @readonly
|
||||
*/
|
||||
get nickMention() {
|
||||
return `<@!${this.id}>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this is a non-user bot object such as webhook-bot.
|
||||
* @return {boolean}
|
||||
*/
|
||||
get isWebhook() {
|
||||
const nonUserBot =
|
||||
this.bot && this.discriminator === Constants.NON_USER_BOT_DISCRIMINATOR;
|
||||
return !!this._webhookUser || nonUserBot;
|
||||
}
|
||||
}
|
||||
|
||||
IUser._inherit(User, function modelPropertyGetter(key) {
|
||||
if (this._webhookUser) return this._webhookUser[key];
|
||||
return this._discordie._users.get(this._userId)[key];
|
||||
});
|
||||
|
||||
module.exports = IUser;
|
256
node_modules/discordie/lib/interfaces/IUserCollection.js
generated
vendored
Normal file
256
node_modules/discordie/lib/interfaces/IUserCollection.js
generated
vendored
Normal file
@ -0,0 +1,256 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const StatusTypes = Constants.StatusTypes;
|
||||
const Permissions = Constants.Permissions;
|
||||
const ICollectionBase = require("./ICollectionBase");
|
||||
const IGuild = require("./IGuild");
|
||||
const IGuildMember = require("./IGuildMember");
|
||||
const IChannel = require("./IChannel");
|
||||
const IUser = require("./IUser");
|
||||
const IDirectMessageChannel = require("./IDirectMessageChannel");
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @extends ICollectionBase
|
||||
*/
|
||||
class IUserCollection extends ICollectionBase {
|
||||
constructor(discordie, valuesGetter, valueGetter) {
|
||||
super({
|
||||
valuesGetter: valuesGetter,
|
||||
valueGetter: valueGetter,
|
||||
itemFactory: (id) => new IUser(this._discordie, id)
|
||||
});
|
||||
Utils.definePrivate(this, {_discordie: discordie});
|
||||
}
|
||||
|
||||
/**
|
||||
* Request members and wait until cache populates for all guilds or
|
||||
* an array of guilds.
|
||||
* Request is made over gateway websocket.
|
||||
*
|
||||
* Will request members for all guilds if no arguments passed.
|
||||
*
|
||||
* By default Discord sends only online members if there are more than 250
|
||||
* (offline and online total) joined in a guild.
|
||||
*
|
||||
* Returned promise will resolve when all members have been fetched.
|
||||
* Returned promise will reject if all or some members have not been received
|
||||
* within 60 seconds or primary gateway websocket disconnected.
|
||||
*
|
||||
* If all members for chosen guilds are already in cache - returns a
|
||||
* resolved promise.
|
||||
*
|
||||
* > **Note:** When guilds become unavailable or deleted
|
||||
* > (events `GUILD_UNAVAILABLE` and `GUILD_DELETE`)
|
||||
* > all members will also be deleted from cache.
|
||||
* @param {IGuild|String|Array<IGuild|String>} [guilds]
|
||||
* @returns {Promise}
|
||||
* @example
|
||||
* client.Users.fetchMembers()
|
||||
* .then(() => console.log("Received members for all guilds"));
|
||||
*
|
||||
* client.Users.fetchMembers([guild1, guild2, guild3])
|
||||
* .then(() => console.log("Received members for 3 guilds"));
|
||||
*
|
||||
* var p1 = client.Users.fetchMembers(guild1);
|
||||
* p1.catch(err => console.log("Failed to receive guild1 members: " + err));
|
||||
* var p2 = client.Users.fetchMembers(guild2);
|
||||
* var p3 = client.Users.fetchMembers(guild3);
|
||||
* Promise.all([p1, p2, p3])
|
||||
* .then(() => console.log("Received members for 3 guilds"));
|
||||
* .catch(err => console.log("Failed to receive some members: " + err));
|
||||
*/
|
||||
fetchMembers(guilds) {
|
||||
if (guilds) {
|
||||
if (guilds.map) guilds = guilds.map(guild => guild.valueOf());
|
||||
else guilds = [guilds.valueOf()];
|
||||
}
|
||||
return this._discordie._members.fetchMembers(guilds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `IGuildMember` for specified `user` of `guild`.
|
||||
*
|
||||
* Returns null if the user is not a member of the guild.
|
||||
* @param {IGuild|String} guild - Guild or an id string
|
||||
* @param {IUser|String} user - User or an id string
|
||||
* @returns {IGuildMember|null}
|
||||
*/
|
||||
getMember(guild, user) {
|
||||
guild = guild.valueOf();
|
||||
user = user.valueOf();
|
||||
var member = this._discordie._members.getMember(guild, user);
|
||||
if (!member) return null;
|
||||
return this._getOrCreateInterface(member,
|
||||
() => new IGuildMember(this._discordie, user, guild)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Creates an array of `IGuildMember` for `guild`.
|
||||
* @param {IGuild|String} guild - Guild or an id string
|
||||
* @returns {Array<IGuildMember>}
|
||||
*/
|
||||
membersForGuild(guild) {
|
||||
guild = guild.valueOf();
|
||||
|
||||
const members = [];
|
||||
const guildMembers = this._discordie._members.get(guild);
|
||||
if (!guildMembers) return members;
|
||||
for (var member of guildMembers.values()) {
|
||||
members.push(this._getOrCreateInterface(member,
|
||||
() => new IGuildMember(this._discordie, member.id, guild)
|
||||
));
|
||||
}
|
||||
return members;
|
||||
}
|
||||
/**
|
||||
* Creates an array of `IGuildMember` that have permissions to read `channel`.
|
||||
*
|
||||
* > **Note:** This method computes permissions for all members and may be CPU
|
||||
* > intensive for large guilds.
|
||||
* @param {ITextChannel|String} channel - Channel or an id string
|
||||
* @returns {Array<IGuildMember>}
|
||||
*/
|
||||
membersForChannel(channel) {
|
||||
if (!(channel instanceof IChannel))
|
||||
channel = this._discordie.Channels.get(channel);
|
||||
|
||||
if (!channel) return [];
|
||||
|
||||
const guild = channel.guild;
|
||||
if (!guild) throw new Error("Channel does not exist");
|
||||
|
||||
const guildMembers = channel.guild.members;
|
||||
if (!guildMembers) return [];
|
||||
return guildMembers.filter(m =>
|
||||
m.can(Permissions.Text.READ_MESSAGES, channel)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Creates an array of `IGuildMember` containing
|
||||
* active members in a voice `channel`.
|
||||
* @param {IVoiceChannel|String} channel - Channel or an id string
|
||||
* @returns {Array<IGuildMember>}
|
||||
*/
|
||||
membersInVoiceChannel(channel) {
|
||||
if (!(channel instanceof IChannel))
|
||||
channel = this._discordie.Channels.get(channel);
|
||||
|
||||
if (!channel) return [];
|
||||
|
||||
const members = [];
|
||||
const guildMembers = this._discordie._members.get(channel.guild_id);
|
||||
if (!guildMembers) return members;
|
||||
|
||||
const userMap = this._discordie._voicestates.getStatesInChannel(channel.id);
|
||||
for (var id of userMap.keys()) {
|
||||
const member = guildMembers.get(id);
|
||||
if (!member) continue;
|
||||
members.push(this._getOrCreateInterface(member,
|
||||
() => new IGuildMember(this._discordie, id, channel.guild_id)
|
||||
));
|
||||
}
|
||||
return members;
|
||||
}
|
||||
/**
|
||||
* Creates an array of `IUser` containing users in a private voice channel.
|
||||
* @param {IDirectMessageChannel|String} channel - Channel or an id string
|
||||
* @returns {Array<IUser>}
|
||||
*/
|
||||
usersInCall(channel) {
|
||||
if (!(channel instanceof IDirectMessageChannel))
|
||||
channel = this._discordie.DirectMessageChannels.get(channel);
|
||||
|
||||
if (!channel) return [];
|
||||
const users = [];
|
||||
|
||||
const userMap = this._discordie._voicestates.getStatesInChannel(channel.id);
|
||||
for (var id of userMap.keys()) {
|
||||
const user = this.get(id);
|
||||
if (user) users.push(user);
|
||||
}
|
||||
return users;
|
||||
}
|
||||
/**
|
||||
* Creates an array of `IGuildMember` for `guild` that are currently online.
|
||||
* @param {IGuild|String} guild - Guild or an id string
|
||||
* @returns {Array<IGuildMember>}
|
||||
*/
|
||||
onlineMembersForGuild(guild) {
|
||||
guild = guild.valueOf();
|
||||
|
||||
const members = [];
|
||||
const presences = this._discordie._presences;
|
||||
const guildMembers = this._discordie._members.get(guild);
|
||||
if (!guildMembers) return members;
|
||||
for (var member of guildMembers.values()) {
|
||||
if (presences.getStatus(member.id) != StatusTypes.OFFLINE) {
|
||||
members.push(this._getOrCreateInterface(member,
|
||||
() => new IGuildMember(this._discordie, member.id, guild)
|
||||
));
|
||||
}
|
||||
}
|
||||
return members;
|
||||
}
|
||||
/**
|
||||
* Creates an array of `IGuildMember` that
|
||||
* have permissions to read `channel` and currently online.
|
||||
*
|
||||
* > **Note:** This method computes permissions for all members and may be CPU
|
||||
* > intensive for large guilds.
|
||||
* @param {ITextChannel|String} channel - Channel or an id string
|
||||
* @returns {Array<IGuildMember>}
|
||||
*/
|
||||
onlineMembersForChannel(channel) {
|
||||
return this.membersForChannel(channel).filter(
|
||||
m => m.status != StatusTypes.OFFLINE
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Creates an array of `IGuildMember` for `guild` that are currently offline.
|
||||
*
|
||||
* Does not guarantee every offline member unless
|
||||
* `IUserCollection.fetchMembers` has been called for the `guild`.
|
||||
*
|
||||
* @param {IGuild|String} guild - Guild or an id string
|
||||
* @returns {Array<IGuildMember>}
|
||||
*/
|
||||
offlineMembersForGuild(guild) {
|
||||
guild = guild.valueOf();
|
||||
|
||||
const members = [];
|
||||
const presences = this._discordie._presences;
|
||||
const guildMembers = this._discordie._members.get(guild);
|
||||
if (!guildMembers) return members;
|
||||
for (var member of guildMembers.values()) {
|
||||
if (presences.getStatus(member.id) == StatusTypes.OFFLINE) {
|
||||
members.push(this._getOrCreateInterface(member,
|
||||
() => new IGuildMember(this._discordie, member.id, guild)
|
||||
));
|
||||
}
|
||||
}
|
||||
return members;
|
||||
}
|
||||
/**
|
||||
* Creates an array of `IGuildMember` that
|
||||
* have permissions to read `channel` and currently offline.
|
||||
*
|
||||
* Does not guarantee every offline member unless
|
||||
* `IUserCollection.fetchMembers` has been called for the guild the `channel`
|
||||
* belongs to.
|
||||
*
|
||||
* > **Note:** This method computes permissions for all members and may be CPU
|
||||
* > intensive for large guilds.
|
||||
* @param {ITextChannel|String} channel - Channel or an id string
|
||||
* @returns {Array<IGuildMember>}
|
||||
*/
|
||||
offlineMembersForChannel(channel) {
|
||||
return this.membersForChannel(channel).filter(
|
||||
m => m.status == StatusTypes.OFFLINE
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IUserCollection;
|
113
node_modules/discordie/lib/interfaces/IVoiceChannel.js
generated
vendored
Normal file
113
node_modules/discordie/lib/interfaces/IVoiceChannel.js
generated
vendored
Normal file
@ -0,0 +1,113 @@
|
||||
"use strict";
|
||||
|
||||
const Utils = require("../core/Utils");
|
||||
const User = require("../models/User");
|
||||
const IChannel = require("./IChannel");
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @model Channel
|
||||
* @extends IChannel
|
||||
*/
|
||||
class IVoiceChannel extends IChannel {
|
||||
constructor(discordie, channelId) {
|
||||
super(discordie, channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an array of members joined in this voice channels.
|
||||
* @returns {Array<IGuildMember>}
|
||||
* @readonly
|
||||
*/
|
||||
get members() {
|
||||
return this._discordie.Users.membersInVoiceChannel(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether current user is in this voice channel.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get joined() {
|
||||
const vc = this._discordie.VoiceConnections;
|
||||
const pendingChannel = vc.getPendingChannel(this.guild_id);
|
||||
return !!(pendingChannel && pendingChannel === this._channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins this voice channel.
|
||||
* Creates a new voice connection if there are no active connections for
|
||||
* this channels' guild.
|
||||
*
|
||||
* > **Note:** One account can be only in one channel per guild.
|
||||
* > Promise will resolve instantly and contain the same instance
|
||||
* > if connection to the server is already established.
|
||||
*
|
||||
* If there is a pending connection for the guild this channel belongs to,
|
||||
* it will return the same promise.
|
||||
*
|
||||
* Checks permissions locally and returns a rejected promise with:
|
||||
*
|
||||
* - **`Error "Missing permission"`** if `Voice.CONNECT` permission is denied.
|
||||
*
|
||||
* - **`Error "Channel is full"`** if `Voice.MOVE_MEMBERS` permission is
|
||||
* denied and channel is full.
|
||||
*
|
||||
* Returns a rejected promise with **`Error "Channel does not exist"`** if
|
||||
* guild is unavailable or channel does not exist in cache.
|
||||
*
|
||||
* Returned promise can be cancelled or rejected: see `VOICE_DISCONNECTED`
|
||||
* event for more info.
|
||||
*
|
||||
* @param {boolean} [selfMute]
|
||||
* @param {boolean} [selfDeaf]
|
||||
* @returns {Promise<VoiceConnectionInfo, Error|Number>}
|
||||
*/
|
||||
join(selfMute, selfDeaf) {
|
||||
selfMute = !!selfMute;
|
||||
selfDeaf = !!selfDeaf;
|
||||
|
||||
if (!this._valid)
|
||||
return Promise.reject(new Error("Channel does not exist"));
|
||||
|
||||
// check permissions locally
|
||||
// since server silently drops invalid voice state updates
|
||||
if (!this.joined) {
|
||||
const permissions = this._discordie.User.permissionsFor(this);
|
||||
if (!permissions.Voice.CONNECT)
|
||||
return Promise.reject(new Error("Missing permission"));
|
||||
|
||||
if (this.user_limit > 0) {
|
||||
const states = this._discordie._voicestates.getStatesInChannel(this.id);
|
||||
if (states.size >= this.user_limit) {
|
||||
if (!permissions.Voice.MOVE_MEMBERS)
|
||||
return Promise.reject(new Error("Channel is full"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const vc = this._discordie.VoiceConnections;
|
||||
return vc._getOrCreate(this.guild_id, this._channelId, selfMute, selfDeaf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves this voice channel if joined.
|
||||
*/
|
||||
leave() {
|
||||
const info = this.getVoiceConnectionInfo();
|
||||
if (info) return info.voiceConnection.disconnect();
|
||||
|
||||
this._discordie.VoiceConnections
|
||||
.cancelIfPending(this.guild_id, this._channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves `VoiceConnectionInfo` for this voice channel.
|
||||
* @returns {VoiceConnectionInfo|null}
|
||||
*/
|
||||
getVoiceConnectionInfo() {
|
||||
return this._discordie.VoiceConnections.getForChannel(this._channelId);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IVoiceChannel;
|
215
node_modules/discordie/lib/interfaces/IVoiceConnection.js
generated
vendored
Normal file
215
node_modules/discordie/lib/interfaces/IVoiceConnection.js
generated
vendored
Normal file
@ -0,0 +1,215 @@
|
||||
"use strict";
|
||||
|
||||
const Utils = require("../core/Utils");
|
||||
const ExternalEncoderFactory = require("../voice/players/ExternalEncoderFactory");
|
||||
|
||||
function initInterface(_interface, _options) {
|
||||
if (!_interface)
|
||||
throw new TypeError("Invalid interface");
|
||||
if (_options) _interface.initialize(_options);
|
||||
return _interface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface
|
||||
*/
|
||||
class IVoiceConnection {
|
||||
constructor(discordie, gatewaySocket, voiceSocket) {
|
||||
// todo: ssrc to user
|
||||
//discordie.Dispatcher.on(Events.VOICE_SPEAKING, e => {
|
||||
// if (e.socket == voicews) this.emit("speaking", - bla - resolve ssrc)
|
||||
//});
|
||||
|
||||
this._gatewaySocket = gatewaySocket;
|
||||
this._voiceSocket = voiceSocket;
|
||||
this._lastChannelId = null;
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
|
||||
if (!this.canStream)
|
||||
throw new Error("Failed to create IVoiceConnection");
|
||||
}
|
||||
dispose() {
|
||||
this._lastChannelId = this.channelId;
|
||||
this._gatewaySocket = null;
|
||||
this._voiceSocket = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this voice connection is no longer valid.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get disposed() {
|
||||
return !this._voiceSocket;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this voice connection is fully initialized.
|
||||
* @returns {boolean}
|
||||
* @readonly
|
||||
*/
|
||||
get canStream() {
|
||||
return this._voiceSocket && this._voiceSocket.canStream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets channel of this voice connection.
|
||||
*
|
||||
* Returns last channel it was connected to if voice connection has been
|
||||
* disposed.
|
||||
* Returns null if guild became unavailable or channel doesn't exist in cache.
|
||||
* @returns {IChannel|null}
|
||||
* @readonly
|
||||
*/
|
||||
get channel() {
|
||||
const channelId = this.channelId;
|
||||
if (!channelId) return null;
|
||||
return this._discordie.Channels.get(channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets channel id of this voice connection.
|
||||
*
|
||||
* Returns last channel id it was connected to if voice connection has been
|
||||
* disposed.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get channelId() {
|
||||
if (this._lastChannelId) return this._lastChannelId;
|
||||
|
||||
const gw = this._gatewaySocket;
|
||||
if (!gw) return null;
|
||||
|
||||
const voiceState = gw.voiceStates.get(this.guildId);
|
||||
if (!voiceState) return null;
|
||||
|
||||
return voiceState.channelId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets guild of this voice connection.
|
||||
*
|
||||
* Returns null if this is a private call, or guild became unavailable or
|
||||
* doesn't exist in cache.
|
||||
* @returns {IGuild|null}
|
||||
* @readonly
|
||||
*/
|
||||
get guild() {
|
||||
const gw = this._gatewaySocket;
|
||||
if (!gw) return null;
|
||||
return this._discordie.Guilds.get(this.guildId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets guild id of this voice connection.
|
||||
*
|
||||
* Returns null if this is a private call.
|
||||
* @returns {String|null}
|
||||
* @readonly
|
||||
*/
|
||||
get guildId() {
|
||||
return this._voiceSocket ? this._voiceSocket.guildId : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a user object from source id assigned to this voice connection.
|
||||
* @param {Number} ssrc
|
||||
* @returns {IUser}
|
||||
*/
|
||||
ssrcToUser(ssrc) {
|
||||
if (this.disposed) return null;
|
||||
const userid = this._discordie._voicestates.ssrcToUserId(this, ssrc);
|
||||
if (!userid) return null;
|
||||
return this._discordie.Users.get(userid) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves a member object from source id assigned to this voice connection.
|
||||
* @param {Number} ssrc
|
||||
* @returns {IGuildMember}
|
||||
*/
|
||||
ssrcToMember(ssrc) {
|
||||
if (this.disposed) return null;
|
||||
const userid = this._discordie._voicestates.ssrcToUserId(this, ssrc);
|
||||
if (!userid) return null;
|
||||
return this._discordie.Users.getMember(this.guild, userid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes encoder and gets stream for this voice connection.
|
||||
*
|
||||
* Calls without arguments return existing encoder without reinitialization.
|
||||
*
|
||||
* See `AudioEncoder.initialize()` method for list of options.
|
||||
* @param [options]
|
||||
* @returns {AudioEncoderStream}
|
||||
*/
|
||||
getEncoderStream(options) {
|
||||
const encoder = this.getEncoder(options);
|
||||
if (!encoder) return null;
|
||||
return encoder._stream;
|
||||
}
|
||||
createDecoderStream(options) {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an external encoder.
|
||||
*
|
||||
* Accepts options object with `type` property (default `{type: "ffmpeg"}`).
|
||||
* Each type supports additional options.
|
||||
* See docs for returned classes for usage info.
|
||||
* @param {Object} [options]
|
||||
* @returns {FFmpegEncoder|
|
||||
* OggOpusPlayer|
|
||||
* WebmOpusPlayer}
|
||||
*/
|
||||
createExternalEncoder(options) {
|
||||
if (!this._voiceSocket) return null;
|
||||
return ExternalEncoderFactory.create(this, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes encoder instance for this voice connection.
|
||||
*
|
||||
* Calls without arguments return existing encoder without reinitialization.
|
||||
*
|
||||
* See `AudioEncoder.initialize()` method for list of options.
|
||||
* @param {Object} [options]
|
||||
* @returns {AudioEncoder}
|
||||
*/
|
||||
getEncoder(options) {
|
||||
if (!this._voiceSocket) return null;
|
||||
return initInterface(this._voiceSocket.audioEncoder, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes decoder instance for this voice connection.
|
||||
*
|
||||
* Calls without arguments return existing decoder without reinitialization.
|
||||
* @param {Object} [options]
|
||||
* @returns {AudioDecoder}
|
||||
*/
|
||||
getDecoder(options) {
|
||||
if (!this._voiceSocket) return null;
|
||||
return initInterface(this._voiceSocket.audioDecoder, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects this voice connection.
|
||||
*/
|
||||
disconnect() {
|
||||
this._disconnect();
|
||||
}
|
||||
|
||||
_disconnect(error) {
|
||||
if (!this._gatewaySocket) return;
|
||||
if (this.guildId || this.channelId) {
|
||||
this._gatewaySocket.disconnectVoice(this.guildId, false, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IVoiceConnection;
|
230
node_modules/discordie/lib/interfaces/IWebhookManager.js
generated
vendored
Normal file
230
node_modules/discordie/lib/interfaces/IWebhookManager.js
generated
vendored
Normal file
@ -0,0 +1,230 @@
|
||||
"use strict";
|
||||
|
||||
const Utils = require("../core/Utils");
|
||||
|
||||
const rest = require("../networking/rest");
|
||||
|
||||
function webhookToId(webhook) {
|
||||
if (!webhook) throw new TypeError("Param 'webhook' is invalid");
|
||||
if (typeof webhook === "string") return webhook;
|
||||
return webhook.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* @interface
|
||||
* @description
|
||||
* Wrapper for webhook methods.
|
||||
*
|
||||
* Example webhook object:
|
||||
* ```js
|
||||
* {
|
||||
* "name": "abc",
|
||||
* "channel_id": "78231142373424474",
|
||||
* "token": "EtuNYHGkElBlE7BE266Jk...NzHvccXaUCQUOY64NbFWz9zbQ",
|
||||
* "avatar": null,
|
||||
* "guild_id": "78231498370026660",
|
||||
* "id": "232330225768333313",
|
||||
* "user": {
|
||||
* "username": "testuser",
|
||||
* "discriminator": "3273",
|
||||
* "id": "000000000000000000",
|
||||
* "avatar": null
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class IWebhookManager {
|
||||
constructor(discordie) {
|
||||
this._discordie = discordie;
|
||||
Utils.privatify(this);
|
||||
Object.freeze(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* **Requires logging in with an API token.**
|
||||
*
|
||||
* Makes a request to get webhook objects for the specified guild.
|
||||
* @param {IGuild|String} guild
|
||||
* @return {Promise<Array<Object>, Error>}
|
||||
*/
|
||||
fetchForGuild(guild) {
|
||||
guild = guild.valueOf();
|
||||
return rest(this._discordie).webhooks.getGuildWebhooks(guild);
|
||||
}
|
||||
|
||||
/**
|
||||
* **Requires logging in with an API token.**
|
||||
*
|
||||
* Makes a request to get webhook objects for the specified channel.
|
||||
* @param {IChannel|String} channel
|
||||
* @return {Promise<Array<Object>, Error>}
|
||||
*/
|
||||
fetchForChannel(channel) {
|
||||
channel = channel.valueOf();
|
||||
return rest(this._discordie).webhooks.getChannelWebhooks(channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* **Requires logging in with an API token.**
|
||||
*
|
||||
* Makes a request to create a webhook for the channel.
|
||||
*
|
||||
* Promise resolves with a webhook object.
|
||||
* @param {IChannel} channel
|
||||
* @param {Object} options
|
||||
* Object with properties `{name: String, avatar: Buffer|String|null}`.
|
||||
*
|
||||
* String avatars must be base64 data-url encoded.
|
||||
* @return {Promise<Object, Error>}
|
||||
*/
|
||||
create(channel, options) {
|
||||
channel = channel.valueOf();
|
||||
|
||||
options = options || {};
|
||||
if (options.avatar instanceof Buffer) {
|
||||
options.avatar = Utils.imageToDataURL(options.avatar);
|
||||
}
|
||||
|
||||
return rest(this._discordie).webhooks.createWebhook(channel, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to fetch a webhook object.
|
||||
*
|
||||
* Promise resolves with a webhook object (does not contain a `user` object
|
||||
* if fetched with `token` param).
|
||||
* @param {Object|String} webhook - Webhook object or id.
|
||||
* @param {String} token
|
||||
* Webhook token, not required if currently logged in
|
||||
* with an account that has access to the webhook.
|
||||
* @return {Promise<Object, Error>}
|
||||
*/
|
||||
fetch(webhook, token) {
|
||||
const webhookId = webhookToId(webhook);
|
||||
return rest(this._discordie).webhooks.getWebhook(webhookId, token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to edit the specified webhook.
|
||||
*
|
||||
* Promise resolves with a webhook object (does not contain a `user` object
|
||||
* if edited with `token` param).
|
||||
* @param {Object|String} webhook - Webhook object or id.
|
||||
* @param {String} token
|
||||
* Webhook token, not required and can be set to null if currently logged in
|
||||
* with an account that has access to the webhook.
|
||||
* @param {Object} options
|
||||
* Object with properties `{name: String, avatar: Buffer|String|null}`.
|
||||
*
|
||||
* String avatars must be base64 data-url encoded.
|
||||
* @return {Promise<Object, Error>}
|
||||
*/
|
||||
edit(webhook, token, options) {
|
||||
const webhookId = webhookToId(webhook);
|
||||
|
||||
options = options || {};
|
||||
if (options.avatar instanceof Buffer) {
|
||||
options.avatar = Utils.imageToDataURL(options.avatar);
|
||||
}
|
||||
|
||||
return rest(this._discordie)
|
||||
.webhooks.patchWebhook(webhookId, token, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to delete the specified webhook.
|
||||
* @param {Object|String} webhook - Webhook object or id.
|
||||
* @param {String} token
|
||||
* Webhook token, not required and can be set to null if currently logged in
|
||||
* with an account that has access to the webhook.
|
||||
* @return {Promise}
|
||||
*/
|
||||
delete(webhook, token) {
|
||||
const webhookId = webhookToId(webhook);
|
||||
return rest(this._discordie)
|
||||
.webhooks.deleteWebhook(webhookId, token);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to execute the specified webhook.
|
||||
*
|
||||
* > **Note:** Embeds in file uploads are not supported.
|
||||
* @param {Object|String} webhook - Webhook object or id.
|
||||
* @param {String} token - Required unless webhook object contains token.
|
||||
* @param {Object} options
|
||||
* Refer to [official API documentation](https://discordapp.com/developers/docs/)
|
||||
* for more information.
|
||||
* @param {boolean} [wait]
|
||||
* Wait for server confirmation of message delivery,
|
||||
* returned promise will contain a raw message object or an error if message
|
||||
* creation failed.
|
||||
* @return {Promise}
|
||||
* @example
|
||||
* const webhookId = "232330225768333313";
|
||||
* const token = "EtuNYHGkElBlE7BE266Jk...NzHvccXaUCQUOY64NbFWz9zbQ";
|
||||
* client.Webhooks.execute(webhookId, token, {content: "text message"});
|
||||
* client.Webhooks.execute(webhookId, token, {
|
||||
* // text message
|
||||
* content: "text message",
|
||||
* username: "Different Username",
|
||||
* avatar_url: "https://localhost/test.png",
|
||||
* tts: false,
|
||||
* embeds: [{
|
||||
* color: 0x3498db,
|
||||
* author: {name: "who dis"},
|
||||
* title: "This is an embed",
|
||||
* description: "Nobody will read this anyway",
|
||||
* url: "http://google.com",
|
||||
* timestamp: "2016-10-03T03:32:31.205Z",
|
||||
* fields: [{name: "some field", value: "some value"}],
|
||||
* footer: {text: "footer text"}
|
||||
* }]
|
||||
* });
|
||||
*
|
||||
* client.Webhooks.execute(webhookId, token, {
|
||||
* // file upload
|
||||
* content: "text message",
|
||||
* username: "Different Username",
|
||||
* file: fs.readFileSync("test.png"),
|
||||
* filename: "test.png"
|
||||
* });
|
||||
*/
|
||||
execute(webhook, token, options, wait) {
|
||||
const webhookId = webhookToId(webhook);
|
||||
token = token || webhook.token;
|
||||
return rest(this._discordie)
|
||||
.webhooks.executeWebhook(webhookId, token, options, wait);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request to execute the specified webhook with slack-compatible
|
||||
* options.
|
||||
* @param {Object|String} webhook - Webhook object or id.
|
||||
* @param {String} token - Required unless webhook object contains token.
|
||||
* @param {Object} options
|
||||
* Refer to [Slack's documentation](https://api.slack.com/incoming-webhooks)
|
||||
* for more information.
|
||||
*
|
||||
* Discord does not support Slack's `channel`, `icon_emoji`, `mrkdwn`,
|
||||
* or `mrkdwn_in` properties.
|
||||
* @param {boolean} [wait]
|
||||
* Wait for server confirmation of message delivery, defaults to true.
|
||||
* When set to false, a message that is not saved does not return an error.
|
||||
* @return {Promise}
|
||||
* @example
|
||||
* const webhookId = "232330225768333313";
|
||||
* const token = "EtuNYHGkElBlE7BE266Jk...NzHvccXaUCQUOY64NbFWz9zbQ";
|
||||
* client.Webhooks.executeSlack(webhookId, token, {
|
||||
* text: "text message",
|
||||
* username: "Different Username"
|
||||
* });
|
||||
*/
|
||||
executeSlack(webhook, token, options, wait) {
|
||||
const webhookId = webhookToId(webhook);
|
||||
token = token || webhook.token;
|
||||
return rest(this._discordie)
|
||||
.webhooks.executeSlackWebhook(webhookId, token, options, wait);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = IWebhookManager;
|
44
node_modules/discordie/lib/models/AuthenticatedUser.js
generated
vendored
Normal file
44
node_modules/discordie/lib/models/AuthenticatedUser.js
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const StatusTypes = Constants.StatusTypes;
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias AuthenticatedUser
|
||||
*/
|
||||
const BaseAuthenticatedUser = {
|
||||
/** @returns {String|null} */
|
||||
id: null,
|
||||
/** @returns {String|null} */
|
||||
username: "",
|
||||
/** @returns {String|null} */
|
||||
discriminator: null,
|
||||
/** @returns {String|null} */
|
||||
email: null,
|
||||
/** @returns {boolean|null} */
|
||||
verified: false,
|
||||
/** @returns {String|null} */
|
||||
status: StatusTypes.ONLINE,
|
||||
/** @returns {String|null} */
|
||||
avatar: null,
|
||||
/** @returns {String|null} */
|
||||
token: null,
|
||||
/** @returns {boolean|null} */
|
||||
bot: false,
|
||||
/** @returns {boolean|null} */
|
||||
mfa_enabled: false,
|
||||
/** @returns {Object|null} */
|
||||
game: null, // clientside cache
|
||||
/** @returns {boolean|null} */
|
||||
afk: false // clientside cache
|
||||
};
|
||||
|
||||
class AuthenticatedUser extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BaseAuthenticatedUser, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = AuthenticatedUser;
|
27
node_modules/discordie/lib/models/BaseModel.js
generated
vendored
Normal file
27
node_modules/discordie/lib/models/BaseModel.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
|
||||
class BaseModel {
|
||||
constructor(base, def) {
|
||||
for (let k in base) {
|
||||
this[k] = ((def && def.hasOwnProperty(k)) ? def[k] : base[k]);
|
||||
}
|
||||
Object.freeze(this);
|
||||
}
|
||||
merge(def) {
|
||||
if (!def) {
|
||||
return this;
|
||||
}
|
||||
let merged = {};
|
||||
for (let k in this) {
|
||||
merged[k] = this[k];
|
||||
}
|
||||
for (let k in def) {
|
||||
if (merged.hasOwnProperty(k)) {
|
||||
merged[k] = def[k];
|
||||
}
|
||||
}
|
||||
return new this.constructor(merged);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = BaseModel;
|
29
node_modules/discordie/lib/models/Call.js
generated
vendored
Normal file
29
node_modules/discordie/lib/models/Call.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias Call
|
||||
*/
|
||||
const BaseCall = {
|
||||
/** @returns {String|null} */
|
||||
channel_id: null,
|
||||
/** @returns {String|null} */
|
||||
message_id: null,
|
||||
/** @returns {String|null} */
|
||||
region: null,
|
||||
/** @returns {Array<String>|null} */
|
||||
ringing: [],
|
||||
/** @returns {boolean|null} */
|
||||
unavailable: false
|
||||
};
|
||||
|
||||
class Call extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BaseCall, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Call;
|
44
node_modules/discordie/lib/models/Channel.js
generated
vendored
Normal file
44
node_modules/discordie/lib/models/Channel.js
generated
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const ChannelTypes = Constants.ChannelTypes;
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias Channel
|
||||
*/
|
||||
const BaseChannel = {
|
||||
/** @returns {String|null} */
|
||||
id: null,
|
||||
/** @returns {String|null} */
|
||||
name: "<not initialized>",
|
||||
/** @returns {String|null} */
|
||||
topic: "",
|
||||
/** @returns {Number|null} */
|
||||
position: 0,
|
||||
/** @returns {Number|null} */
|
||||
type: ChannelTypes.GUILD_TEXT,
|
||||
/** @returns {String|null} */
|
||||
guild_id: null,
|
||||
/** @returns {Set|null} */
|
||||
recipients: new Set(),
|
||||
/** @returns {Array|null} */
|
||||
permission_overwrites: [],
|
||||
/** @returns {Number|null} */
|
||||
bitrate: 0,
|
||||
/** @returns {Number|null} */
|
||||
user_limit: 0,
|
||||
/** @returns {String|null} */
|
||||
owner_id: null,
|
||||
/** @returns {String|null} */
|
||||
icon: null
|
||||
};
|
||||
|
||||
class Channel extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BaseChannel, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Channel;
|
53
node_modules/discordie/lib/models/Guild.js
generated
vendored
Normal file
53
node_modules/discordie/lib/models/Guild.js
generated
vendored
Normal file
@ -0,0 +1,53 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias Guild
|
||||
*/
|
||||
const BaseGuild = {
|
||||
/** @returns {String|null} */
|
||||
id: null,
|
||||
/** @returns {String|null} */
|
||||
name: null,
|
||||
/** @returns {String|null} */
|
||||
owner_id: null,
|
||||
/** @returns {String|null} */
|
||||
icon: null,
|
||||
/** @returns {String|null} */
|
||||
splash: null,
|
||||
/** @returns {Set|null} */
|
||||
features: new Set(),
|
||||
/** @returns {Array<Object>|null} */
|
||||
emojis: [],
|
||||
/** @returns {Number|null} */
|
||||
default_message_notifications: 0,
|
||||
/** @returns {Map|null} */
|
||||
roles: new Map(),
|
||||
/** @returns {String|null} */
|
||||
afk_channel_id: null,
|
||||
/** @returns {Number|null} */
|
||||
afk_timeout: null,
|
||||
/** @returns {Number|null} */
|
||||
verification_level: 0,
|
||||
/** @returns {String|null} */
|
||||
region: null,
|
||||
/** @returns {Number|null} */
|
||||
member_count: 0,
|
||||
/** @returns {Boolean|null} */
|
||||
large: false,
|
||||
/** @returns {Number|null} */
|
||||
mfa_level: 0,
|
||||
/** @returns {String|null} */
|
||||
joined_at: ""
|
||||
};
|
||||
|
||||
class Guild extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BaseGuild, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Guild;
|
37
node_modules/discordie/lib/models/GuildMember.js
generated
vendored
Normal file
37
node_modules/discordie/lib/models/GuildMember.js
generated
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias GuildMember
|
||||
*/
|
||||
const BaseGuildMember = {
|
||||
/** @returns {String|null} */
|
||||
id: null,
|
||||
/** @returns {String|null} */
|
||||
guild_id: null,
|
||||
/** @returns {String|null} */
|
||||
nick: null,
|
||||
/** @returns {Array|null} */
|
||||
roles: [],
|
||||
/** @returns {boolean|null} */
|
||||
mute: false,
|
||||
/** @returns {boolean|null} */
|
||||
deaf: false,
|
||||
/** @returns {boolean|null} */
|
||||
self_mute: false,
|
||||
/** @returns {boolean|null} */
|
||||
self_deaf: false,
|
||||
/** @returns {String|null} */
|
||||
joined_at: ""
|
||||
};
|
||||
|
||||
class GuildMember extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BaseGuildMember, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GuildMember;
|
75
node_modules/discordie/lib/models/Message.js
generated
vendored
Normal file
75
node_modules/discordie/lib/models/Message.js
generated
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const MessageTypes = Constants.MessageTypes;
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias Message
|
||||
*/
|
||||
const BaseMessage = {
|
||||
/** @returns {String|null} */
|
||||
id: null,
|
||||
/** @returns {Number|null} */
|
||||
type: MessageTypes.DEFAULT,
|
||||
/** @returns {String|null} */
|
||||
channel_id: null,
|
||||
/** @returns {User|null} */
|
||||
author: null,
|
||||
/** @returns {String|null} */
|
||||
content: "",
|
||||
/** @returns {Array|null} */
|
||||
attachments: [],
|
||||
/** @returns {Array|null} */
|
||||
embeds: [],
|
||||
/** @returns {Array|null} */
|
||||
mentions: [],
|
||||
/** @returns {Array|null} */
|
||||
mention_roles: [],
|
||||
/** @returns {boolean|null} */
|
||||
mention_everyone: false,
|
||||
/** @returns {boolean|null} */
|
||||
tts: false,
|
||||
/** @returns {String|null} */
|
||||
timestamp: "",
|
||||
/** @returns {String|null} */
|
||||
edited_timestamp: null,
|
||||
/** @returns {String|null} */
|
||||
nonce: null,
|
||||
/** @returns {String|null} */
|
||||
webhook_id: null,
|
||||
/** @returns {Array|null} */
|
||||
reactions: [],
|
||||
/** @returns {boolean|null} */
|
||||
pinned: false,
|
||||
/**
|
||||
* Raw MessageCall object:
|
||||
*
|
||||
* ```js
|
||||
* {
|
||||
* // Array of user ids participating in this call,
|
||||
* // only used to check if the call was missed
|
||||
* participants: [ "108721394061205504" ], // Array<String>
|
||||
*
|
||||
* // Timestamp when call ended, null if call is in progress
|
||||
* ended_timestamp: "2016-07-24T06:52:11.860000+00:00" // String | null
|
||||
* }
|
||||
* ```
|
||||
* @returns {Object|null}
|
||||
* @memberOf IMessage
|
||||
* @readonly
|
||||
* */
|
||||
call: null,
|
||||
|
||||
/** @returns {boolean|null} */
|
||||
deleted: false // for clientside cache
|
||||
};
|
||||
|
||||
class Message extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BaseMessage, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Message;
|
27
node_modules/discordie/lib/models/PermissionOverwrite.js
generated
vendored
Normal file
27
node_modules/discordie/lib/models/PermissionOverwrite.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias PermissionOverwrite
|
||||
*/
|
||||
const BasePermissionOverwrite = {
|
||||
/** @returns {String|null} */
|
||||
id: null,
|
||||
/** @returns {String|null} */
|
||||
type: null,
|
||||
/** @returns {Number|null} */
|
||||
allow: 0,
|
||||
/** @returns {Number|null} */
|
||||
deny: 0
|
||||
};
|
||||
|
||||
class PermissionOverwrite extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BasePermissionOverwrite, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = PermissionOverwrite;
|
35
node_modules/discordie/lib/models/Role.js
generated
vendored
Normal file
35
node_modules/discordie/lib/models/Role.js
generated
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias Role
|
||||
*/
|
||||
const BaseRole = {
|
||||
/** @returns {String|null} */
|
||||
id: null,
|
||||
/** @returns {String|null} */
|
||||
name: null,
|
||||
/** @returns {Number|null} */
|
||||
permissions: 0,
|
||||
/** @returns {boolean|null} */
|
||||
mentionable: false,
|
||||
/** @returns {Number|null} */
|
||||
position: -1,
|
||||
/** @returns {boolean|null} */
|
||||
hoist: false,
|
||||
/** @returns {Number|null} */
|
||||
color: 0,
|
||||
/** @returns {boolean|null} */
|
||||
managed: false
|
||||
};
|
||||
|
||||
class Role extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BaseRole, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Role;
|
29
node_modules/discordie/lib/models/User.js
generated
vendored
Normal file
29
node_modules/discordie/lib/models/User.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../Constants");
|
||||
const BaseModel = require("./BaseModel");
|
||||
|
||||
/**
|
||||
* @kind model
|
||||
* @alias User
|
||||
*/
|
||||
const BaseUser = {
|
||||
/** @returns {String|null} */
|
||||
id: null,
|
||||
/** @returns {String|null} */
|
||||
username: "",
|
||||
/** @returns {String|null} */
|
||||
discriminator: null,
|
||||
/** @returns {String|null} */
|
||||
avatar: null,
|
||||
/** @returns {boolean|null} */
|
||||
bot: false,
|
||||
};
|
||||
|
||||
class User extends BaseModel {
|
||||
constructor(def) {
|
||||
super(BaseUser, def);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = User;
|
5
node_modules/discordie/lib/networking/messages/MessageValidator.js
generated
vendored
Normal file
5
node_modules/discordie/lib/networking/messages/MessageValidator.js
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
"use strict";
|
||||
|
||||
module.exports = function(schema, data) {
|
||||
|
||||
};
|
18
node_modules/discordie/lib/networking/messages/gateway/call_create.js
generated
vendored
Normal file
18
node_modules/discordie/lib/networking/messages/gateway/call_create.js
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
const channel = this.DirectMessageChannels.get(data.channel_id);
|
||||
if (!channel) return true;
|
||||
|
||||
this.Dispatcher.emit(Events.CALL_CREATE, {
|
||||
socket: gw,
|
||||
channel: channel,
|
||||
call: channel.call
|
||||
});
|
||||
return true;
|
||||
};
|
27
node_modules/discordie/lib/networking/messages/gateway/call_delete.js
generated
vendored
Normal file
27
node_modules/discordie/lib/networking/messages/gateway/call_delete.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
const channel = this.DirectMessageChannels.get(data.channel_id);
|
||||
if (!channel) return true;
|
||||
|
||||
if (data.unavailable) {
|
||||
this.Dispatcher.emit(Events.CALL_UNAVAILABLE, {
|
||||
socket: gw,
|
||||
channelId: data.channel_id,
|
||||
data: data
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
this.Dispatcher.emit(Events.CALL_DELETE, {
|
||||
socket: gw,
|
||||
channelId: data.channel_id,
|
||||
data: data
|
||||
});
|
||||
return true;
|
||||
};
|
18
node_modules/discordie/lib/networking/messages/gateway/call_update.js
generated
vendored
Normal file
18
node_modules/discordie/lib/networking/messages/gateway/call_update.js
generated
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
const channel = this.DirectMessageChannels.get(data.channel_id);
|
||||
if (!channel) return true;
|
||||
|
||||
this.Dispatcher.emit(Events.CALL_UPDATE, {
|
||||
socket: gw,
|
||||
channel: channel,
|
||||
call: channel.call
|
||||
});
|
||||
return true;
|
||||
};
|
14
node_modules/discordie/lib/networking/messages/gateway/channel_create.js
generated
vendored
Normal file
14
node_modules/discordie/lib/networking/messages/gateway/channel_create.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
this.Dispatcher.emit(Events.CHANNEL_CREATE, {
|
||||
socket: gw,
|
||||
channel: this.Channels.get(data.id) ||
|
||||
this.DirectMessageChannels.get(data.id)
|
||||
});
|
||||
return true;
|
||||
};
|
14
node_modules/discordie/lib/networking/messages/gateway/channel_delete.js
generated
vendored
Normal file
14
node_modules/discordie/lib/networking/messages/gateway/channel_delete.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
this.Dispatcher.emit(Events.CHANNEL_DELETE, {
|
||||
socket: gw,
|
||||
channelId: data.id,
|
||||
data: data
|
||||
});
|
||||
return true;
|
||||
};
|
19
node_modules/discordie/lib/networking/messages/gateway/channel_recipient_add.js
generated
vendored
Normal file
19
node_modules/discordie/lib/networking/messages/gateway/channel_recipient_add.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
const channel = this.DirectMessageChannels.get(data.channel_id);
|
||||
const user = this.Users.get(data.user && data.user.id);
|
||||
if (!channel || !user) return true;
|
||||
|
||||
this.Dispatcher.emit(Events.CHANNEL_RECIPIENT_ADD, {
|
||||
socket: gw,
|
||||
channel: channel,
|
||||
user: user
|
||||
});
|
||||
return true;
|
||||
};
|
19
node_modules/discordie/lib/networking/messages/gateway/channel_recipient_remove.js
generated
vendored
Normal file
19
node_modules/discordie/lib/networking/messages/gateway/channel_recipient_remove.js
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
const channel = this.DirectMessageChannels.get(data.channel_id);
|
||||
const user = this.Users.get(data.user && data.user.id);
|
||||
if (!channel || !user) return true;
|
||||
|
||||
this.Dispatcher.emit(Events.CHANNEL_RECIPIENT_REMOVE, {
|
||||
socket: gw,
|
||||
channel: channel,
|
||||
user: user
|
||||
});
|
||||
return true;
|
||||
};
|
25
node_modules/discordie/lib/networking/messages/gateway/channel_update.js
generated
vendored
Normal file
25
node_modules/discordie/lib/networking/messages/gateway/channel_update.js
generated
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../../../core/Utils");
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
const prev = data._prev; delete data._prev;
|
||||
const next = data._next; delete data._next;
|
||||
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
if (!this.Dispatcher.hasListeners(Events.CHANNEL_UPDATE)) return true;
|
||||
|
||||
this.Dispatcher.emit(Events.CHANNEL_UPDATE, {
|
||||
socket: gw,
|
||||
channel: this.Channels.get(data.id) ||
|
||||
this.DirectMessageChannels.get(data.id),
|
||||
getChanges: () => ({
|
||||
before: Utils.modelToObject(prev),
|
||||
after: Utils.modelToObject(next)
|
||||
})
|
||||
});
|
||||
return true;
|
||||
};
|
14
node_modules/discordie/lib/networking/messages/gateway/guild_ban_add.js
generated
vendored
Normal file
14
node_modules/discordie/lib/networking/messages/gateway/guild_ban_add.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
this.Dispatcher.emit(Events.GUILD_BAN_ADD, {
|
||||
socket: gw,
|
||||
guild: this.Guilds.get(data.guild_id),
|
||||
user: this.Users.get(data.user.id)
|
||||
});
|
||||
return true;
|
||||
};
|
14
node_modules/discordie/lib/networking/messages/gateway/guild_ban_remove.js
generated
vendored
Normal file
14
node_modules/discordie/lib/networking/messages/gateway/guild_ban_remove.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
this.Dispatcher.emit(Events.GUILD_BAN_REMOVE, {
|
||||
socket: gw,
|
||||
guild: this.Guilds.get(data.guild_id),
|
||||
user: this.Users.get(data.user.id)
|
||||
});
|
||||
return true;
|
||||
};
|
22
node_modules/discordie/lib/networking/messages/gateway/guild_create.js
generated
vendored
Normal file
22
node_modules/discordie/lib/networking/messages/gateway/guild_create.js
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
if (data.unavailable) {
|
||||
this.Dispatcher.emit(Events.GUILD_UNAVAILABLE, {
|
||||
socket: gw,
|
||||
guildId: data.id
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
this.Dispatcher.emit(Events.GUILD_CREATE, {
|
||||
socket: gw,
|
||||
guild: this.Guilds.get(data.id),
|
||||
becameAvailable: this.UnavailableGuilds.isGuildAvailable(data)
|
||||
});
|
||||
return true;
|
||||
};
|
29
node_modules/discordie/lib/networking/messages/gateway/guild_delete.js
generated
vendored
Normal file
29
node_modules/discordie/lib/networking/messages/gateway/guild_delete.js
generated
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../../../core/Utils");
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
if (data.unavailable) {
|
||||
this.Dispatcher.emit(Events.GUILD_UNAVAILABLE, {
|
||||
socket: gw,
|
||||
guildId: data.id,
|
||||
data: data
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
const cached = data._cached; delete data._cached;
|
||||
|
||||
if (!this.Dispatcher.hasListeners(Events.GUILD_DELETE)) return true;
|
||||
|
||||
this.Dispatcher.emit(Events.GUILD_DELETE, {
|
||||
socket: gw,
|
||||
guildId: data.id,
|
||||
data: data,
|
||||
getCachedData: () => Utils.modelToObject(cached || null)
|
||||
});
|
||||
return true;
|
||||
};
|
27
node_modules/discordie/lib/networking/messages/gateway/guild_emojis_update.js
generated
vendored
Normal file
27
node_modules/discordie/lib/networking/messages/gateway/guild_emojis_update.js
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../../../core/Utils");
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
const prev = data._prev; delete data._prev;
|
||||
const next = data._next; delete data._next;
|
||||
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
if (!this.Dispatcher.hasListeners(Events.GUILD_EMOJIS_UPDATE)) return true;
|
||||
|
||||
const guild = this.Guilds.get(data.guild_id);
|
||||
if (!guild) return;
|
||||
|
||||
this.Dispatcher.emit(Events.GUILD_EMOJIS_UPDATE, {
|
||||
socket: gw,
|
||||
guild: guild,
|
||||
getChanges: () => ({
|
||||
before: Utils.modelToObject(prev),
|
||||
after: Utils.modelToObject(next)
|
||||
})
|
||||
});
|
||||
return true;
|
||||
};
|
14
node_modules/discordie/lib/networking/messages/gateway/guild_member_add.js
generated
vendored
Normal file
14
node_modules/discordie/lib/networking/messages/gateway/guild_member_add.js
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
this.Dispatcher.emit(Events.GUILD_MEMBER_ADD, {
|
||||
socket: gw,
|
||||
guild: this.Guilds.get(data.guild_id),
|
||||
member: this.Users.getMember(data.guild_id, data.user.id)
|
||||
});
|
||||
return true;
|
||||
};
|
24
node_modules/discordie/lib/networking/messages/gateway/guild_member_remove.js
generated
vendored
Normal file
24
node_modules/discordie/lib/networking/messages/gateway/guild_member_remove.js
generated
vendored
Normal file
@ -0,0 +1,24 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../../../core/Utils");
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
const cached = data._cached; delete data._cached;
|
||||
|
||||
if (!this.Dispatcher.hasListeners(Events.GUILD_MEMBER_REMOVE)) return true;
|
||||
|
||||
if (data.user && data.user.id === this._user.id) return true;
|
||||
|
||||
this.Dispatcher.emit(Events.GUILD_MEMBER_REMOVE, {
|
||||
socket: gw,
|
||||
guild: this.Guilds.get(data.guild_id),
|
||||
user: this.Users.get(data.user.id),
|
||||
data: data,
|
||||
getCachedData: () => Utils.modelToObject(cached || null)
|
||||
});
|
||||
return true;
|
||||
};
|
59
node_modules/discordie/lib/networking/messages/gateway/guild_member_update.js
generated
vendored
Normal file
59
node_modules/discordie/lib/networking/messages/gateway/guild_member_update.js
generated
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
const Utils = require("../../../core/Utils");
|
||||
const IRole = require("../../../interfaces/IRole");
|
||||
|
||||
function diffArray(a, b) {
|
||||
return a.filter(id => b.indexOf(id) < 0);
|
||||
}
|
||||
|
||||
function filterExistingRoles(roleIds, guildId) {
|
||||
const guild = this._guilds.get(guildId);
|
||||
if (!guild) return [];
|
||||
return roleIds.filter(id => guild.roles.get(id));
|
||||
}
|
||||
function mapRoles(ids, guildId) {
|
||||
return filterExistingRoles.call(this, ids, guildId)
|
||||
.map(id => new IRole(this, id, guildId));
|
||||
}
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
const prev = data._prev; delete data._prev;
|
||||
const next = data._next; delete data._next;
|
||||
|
||||
if (!gw.isPrimary) return true;
|
||||
|
||||
if (!this.Dispatcher.hasListeners(Events.GUILD_MEMBER_UPDATE)) return true;
|
||||
|
||||
const event = {
|
||||
socket: gw,
|
||||
guild: this.Guilds.get(data.guild_id),
|
||||
member: this.Users.getMember(data.guild_id, data.user.id),
|
||||
rolesAdded: [],
|
||||
rolesRemoved: [],
|
||||
previousNick: null,
|
||||
getChanges: () => ({
|
||||
before: Utils.modelToObject(prev),
|
||||
after: Utils.modelToObject(next)
|
||||
})
|
||||
};
|
||||
|
||||
if (prev && next) {
|
||||
if (Array.isArray(prev.roles) && Array.isArray(next.roles)) {
|
||||
const rolesAdded = diffArray(next.roles, prev.roles);
|
||||
const rolesRemoved = diffArray(prev.roles, next.roles);
|
||||
const rolesChanged = rolesAdded.length || rolesRemoved.length;
|
||||
if (rolesChanged) {
|
||||
event.rolesAdded = mapRoles.call(this, rolesAdded, data.guild_id);
|
||||
event.rolesRemoved = mapRoles.call(this, rolesRemoved, data.guild_id);
|
||||
}
|
||||
}
|
||||
|
||||
event.previousNick = prev.nick;
|
||||
}
|
||||
|
||||
this.Dispatcher.emit(Events.GUILD_MEMBER_UPDATE, event);
|
||||
return true;
|
||||
};
|
15
node_modules/discordie/lib/networking/messages/gateway/guild_role_create.js
generated
vendored
Normal file
15
node_modules/discordie/lib/networking/messages/gateway/guild_role_create.js
generated
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
"use strict";
|
||||
|
||||
const Constants = require("../../../Constants");
|
||||
const Events = Constants.Events;
|
||||
const IRole = require("../../../interfaces/IRole");
|
||||
|
||||
module.exports = function handler(data, gw) {
|
||||
if (!gw.isPrimary) return true;
|
||||
this.Dispatcher.emit(Events.GUILD_ROLE_CREATE, {
|
||||
socket: gw,
|
||||
guild: this.Guilds.get(data.guild_id),
|
||||
role: new IRole(this, data.role.id, data.guild_id)
|
||||
});
|
||||
return true;
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user