diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index 9dfaf7b22..4566284f4 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -9,10 +9,6 @@ jobs: deploy-docs: runs-on: ubuntu-latest - strategy: - matrix: - package: [ "nyxx", "nyxx_commander", "nyxx_extensions", "nyxx_interactions", "nyxx_lavalink" ] - steps: - name: Cache uses: actions/cache@v2 @@ -29,11 +25,9 @@ jobs: uses: actions/checkout@v2.3.4 - name: Install dependencies - working-directory: ./${{ matrix.package }} run: dart pub get - name: Generate docs - working-directory: ./${{ matrix.package }} run: dartdoc - name: Deploy nyxx dev docs @@ -41,7 +35,7 @@ jobs: env: SSH_PRIVATE_KEY: ${{ secrets.DEPLOY_SSH_SERVER_KEY }} ARGS: "-rltDzvO" - SOURCE: "${{ matrix.package }}/doc/api/" + SOURCE: "doc/api/" REMOTE_HOST: ${{ secrets.DEPLOY_REMOTE_HOST }} REMOTE_USER: ${{ secrets.DEPLOY_REMOTE_USER }} - TARGET: "${{ secrets.DEPLOY_REMOTE_TARGET }}/dartdocs/${{ matrix.package }}/" + TARGET: "${{ secrets.DEPLOY_REMOTE_TARGET }}/dartdocs/nyxx" diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml index 439122b2c..89e6f9226 100644 --- a/.github/workflows/integration_tests.yml +++ b/.github/workflows/integration_tests.yml @@ -27,54 +27,15 @@ jobs: uses: actions/checkout@v2.3.4 - name: Install dependencies - working-directory: ./nyxx run: dart pub get - name: Analyze project source - working-directory: ./nyxx run: dart analyze - name: Compile tests - working-directory: ./nyxx/test + working-directory: ./test run: dart2native travis.dart - name: Run tests - working-directory: ./nyxx/test + working-directory: ./test run: ./travis.exe - - test-commander: - name: Tests commander package - needs: [test-nyxx] - runs-on: ubuntu-latest - env: - TEST_TOKEN: ${{ secrets.TEST_TOKEN }} - steps: - - name: Cache - uses: actions/cache@v2 - with: - path: ~/.pub_cache - key: ${{ runner.os }} - - - name: Setup Dart Action - uses: cedx/setup-dart@v2.3.0 - with: - release-channel: stable - - - name: Checkout - uses: actions/checkout@v2.3.4 - - - name: Install dependencies - working-directory: ./nyxx_commander - run: dart pub get - - - name: Analyze project source - working-directory: ./nyxx_commander - run: dart analyze - - - name: Compile tests - working-directory: ./nyxx_commander/test - run: dart2native commander-test.dart - - - name: Run tests - working-directory: ./nyxx_commander/test - run: ./commander-test.exe diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 1dbb824a8..fa3ee1420 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,9 +10,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - run: | - cp README.md ./nyxx/README.md - cp -f LICENSE ./nyxx/LICENSE - name: 'publish nyxx package to pub.dev' id: publish uses: k-paxian/dart-package-publisher@master @@ -21,34 +18,6 @@ jobs: force: true suppressBuildRunner: true credentialJson: ${{ secrets.CREDENTIAL_JSON }} - relativePath: nyxx - - name: 'Commit release tag' - if: steps.publish.outputs.success - uses: hole19/git-tag-action@master - env: - TAG: ${{steps.publish.outputs.package}}-${{steps.publish.outputs.localVersion}} - GITHUB_TOKEN: ${{ secrets.TAG_RELEASE_TOKEN }} - - subpackages_publish: - needs: [nyxx_publish] - runs-on: ubuntu-latest - - strategy: - matrix: - package: ["nyxx_commander", "nyxx_extensions", "nyxx_interactions", "nyxx_lavalink"] - - steps: - - uses: actions/checkout@v2 - - run: cp -f LICENSE ./${{ matrix.package }}/LICENSE - - name: 'publish ${{ matrix.package }} to pub.dev' - id: publish - uses: k-paxian/dart-package-publisher@master - with: - skipTests: true - force: true - suppressBuildRunner: true - credentialJson: ${{ secrets.CREDENTIAL_JSON }} - relativePath: ${{ matrix.package }} - name: 'Commit release tag' if: steps.publish.outputs.success uses: hole19/git-tag-action@master diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 125ed5d0f..2eaa52a72 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -28,83 +28,10 @@ jobs: uses: actions/checkout@v2.3.4 - name: Install dependencies - working-directory: ./nyxx run: dart pub get - name: Analyze project source - working-directory: ./nyxx run: dart analyze - name: Unit tests - working-directory: ./nyxx - run: dart test test/unit.dart - - analyze-subpackages: - needs: [ test-nyxx ] - runs-on: ubuntu-latest - env: - TEST_TOKEN: ${{ secrets.TEST_TOKEN }} - - strategy: - matrix: - package: [ "nyxx_commander", "nyxx_lavalink" ] - - steps: - - name: Cache - uses: actions/cache@v2 - with: - path: ~/.pub_cache - key: ${{ runner.os }} - - - name: Setup Dart Action - uses: cedx/setup-dart@v2.3.0 - with: - release-channel: stable - - - name: Checkout - uses: actions/checkout@v2.3.4 - - - name: Install dependencies - working-directory: ./${{ matrix.package }} - run: dart pub get - - - name: Analyze project source - working-directory: ./${{ matrix.package }} - run: dart analyze - - test-subpackages: - needs: [ test-nyxx ] - runs-on: ubuntu-latest - env: - TEST_TOKEN: ${{ secrets.TEST_TOKEN }} - - strategy: - matrix: - package: [ "nyxx_extensions", "nyxx_interactions" ] - - steps: - - name: Cache - uses: actions/cache@v2 - with: - path: ~/.pub_cache - key: ${{ runner.os }} - - - name: Setup Dart Action - uses: cedx/setup-dart@v2.3.0 - with: - release-channel: stable - - - name: Checkout - uses: actions/checkout@v2.3.4 - - - name: Install dependencies - working-directory: ./${{ matrix.package }} - run: dart pub get - - - name: Analyze project source - working-directory: ./${{ matrix.package }} - run: dart analyze - - - name: Unit tests - working-directory: ./${{ matrix.package }} run: dart test test/unit.dart diff --git a/nyxx/CHANGELOG.md b/CHANGELOG.md similarity index 100% rename from nyxx/CHANGELOG.md rename to CHANGELOG.md diff --git a/README.md b/README.md index b5fc87871..d8553f02a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # nyxx -[![Discord Shield](https://discordapp.com/api/guilds/846136758470443069/widget.png?style=shield)](https://discord.gg/m3tNPpwmRg) [![pub](https://img.shields.io/pub/v/nyxx.svg)](https://pub.dartlang.org/packages/nyxx) [![documentation](https://img.shields.io/badge/Documentation-nyxx-yellow.svg)](https://www.dartdocs.org/documentation/nyxx/latest/) [![documentation](https://img.shields.io/badge/Documentation-nyxx.commander-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.commander/latest/) @@ -34,7 +33,7 @@ void main() { bot.onMessageReceived.listen((event) { if (event.message.content == "!ping") { - event.message.channel.sendMessage(MessageBuilder.content("Pong!")); + event.message.channel.getFromCache()?.sendMessage(content: "Pong!"); } }); } @@ -62,7 +61,7 @@ void main() { final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); Commander(bot, prefix: "!!!") - ..registerCommand("ping", (context, message) => context.reply(MessageBuilder.content("Pong!"))); + ..registerCommand("ping", (context, message) => context.reply(content: "Pong!")); } ``` @@ -70,9 +69,9 @@ void main() { Nyxx examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx/example). -Commander examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx_commander/example) +Commander examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx.commander/example) -Slash commands (interactions) examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx_interactions/example) +Slash commands (interactions) examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx.interactions/example) ### Example bots - [Running on Dart](https://github.com/l7ssha/running_on_dart) @@ -101,6 +100,6 @@ Wiki documentation are designed to match the latest Nyxx release. Read [contributing document](https://github.com/l7ssha/nyxx/blob/development/CONTRIBUTING.md) -## Credits +## Credits - * [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx). +* [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx). diff --git a/nyxx/analysis_options.yaml b/analysis_options.yaml similarity index 100% rename from nyxx/analysis_options.yaml rename to analysis_options.yaml diff --git a/nyxx/example/channel.dart b/example/channel.dart similarity index 100% rename from nyxx/example/channel.dart rename to example/channel.dart diff --git a/nyxx/example/create-add-role.dart b/example/create-add-role.dart similarity index 100% rename from nyxx/example/create-add-role.dart rename to example/create-add-role.dart diff --git a/nyxx/example/embeds.dart b/example/embeds.dart similarity index 100% rename from nyxx/example/embeds.dart rename to example/embeds.dart diff --git a/nyxx/example/example.dart b/example/example.dart similarity index 100% rename from nyxx/example/example.dart rename to example/example.dart diff --git a/nyxx/example/invite.dart b/example/invite.dart similarity index 100% rename from nyxx/example/invite.dart rename to example/invite.dart diff --git a/nyxx/example/kick-ban.dart b/example/kick-ban.dart similarity index 100% rename from nyxx/example/kick-ban.dart rename to example/kick-ban.dart diff --git a/nyxx/example/permissions.dart b/example/permissions.dart similarity index 100% rename from nyxx/example/permissions.dart rename to example/permissions.dart diff --git a/nyxx/example/ping-pong.dart b/example/ping-pong.dart similarity index 100% rename from nyxx/example/ping-pong.dart rename to example/ping-pong.dart diff --git a/nyxx/example/reply-to-message.dart b/example/reply-to-message.dart similarity index 100% rename from nyxx/example/reply-to-message.dart rename to example/reply-to-message.dart diff --git a/nyxx/example/sending-file.dart b/example/sending-file.dart similarity index 100% rename from nyxx/example/sending-file.dart rename to example/sending-file.dart diff --git a/nyxx/lib/nyxx.dart b/lib/nyxx.dart similarity index 100% rename from nyxx/lib/nyxx.dart rename to lib/nyxx.dart diff --git a/nyxx/lib/src/ClientOptions.dart b/lib/src/ClientOptions.dart similarity index 100% rename from nyxx/lib/src/ClientOptions.dart rename to lib/src/ClientOptions.dart diff --git a/nyxx/lib/src/Nyxx.dart b/lib/src/Nyxx.dart similarity index 100% rename from nyxx/lib/src/Nyxx.dart rename to lib/src/Nyxx.dart diff --git a/nyxx/lib/src/core/AllowedMentions.dart b/lib/src/core/AllowedMentions.dart similarity index 100% rename from nyxx/lib/src/core/AllowedMentions.dart rename to lib/src/core/AllowedMentions.dart diff --git a/nyxx/lib/src/core/DiscordColor.dart b/lib/src/core/DiscordColor.dart similarity index 100% rename from nyxx/lib/src/core/DiscordColor.dart rename to lib/src/core/DiscordColor.dart diff --git a/nyxx/lib/src/core/Invite.dart b/lib/src/core/Invite.dart similarity index 100% rename from nyxx/lib/src/core/Invite.dart rename to lib/src/core/Invite.dart diff --git a/nyxx/lib/src/core/Snowflake.dart b/lib/src/core/Snowflake.dart similarity index 100% rename from nyxx/lib/src/core/Snowflake.dart rename to lib/src/core/Snowflake.dart diff --git a/nyxx/lib/src/core/SnowflakeEntity.dart b/lib/src/core/SnowflakeEntity.dart similarity index 100% rename from nyxx/lib/src/core/SnowflakeEntity.dart rename to lib/src/core/SnowflakeEntity.dart diff --git a/nyxx/lib/src/core/application/AppTeam.dart b/lib/src/core/application/AppTeam.dart similarity index 100% rename from nyxx/lib/src/core/application/AppTeam.dart rename to lib/src/core/application/AppTeam.dart diff --git a/nyxx/lib/src/core/application/ClientOAuth2Application.dart b/lib/src/core/application/ClientOAuth2Application.dart similarity index 100% rename from nyxx/lib/src/core/application/ClientOAuth2Application.dart rename to lib/src/core/application/ClientOAuth2Application.dart diff --git a/nyxx/lib/src/core/application/OAuth2Application.dart b/lib/src/core/application/OAuth2Application.dart similarity index 100% rename from nyxx/lib/src/core/application/OAuth2Application.dart rename to lib/src/core/application/OAuth2Application.dart diff --git a/nyxx/lib/src/core/application/OAuth2Guild.dart b/lib/src/core/application/OAuth2Guild.dart similarity index 100% rename from nyxx/lib/src/core/application/OAuth2Guild.dart rename to lib/src/core/application/OAuth2Guild.dart diff --git a/nyxx/lib/src/core/application/OAuth2Info.dart b/lib/src/core/application/OAuth2Info.dart similarity index 100% rename from nyxx/lib/src/core/application/OAuth2Info.dart rename to lib/src/core/application/OAuth2Info.dart diff --git a/nyxx/lib/src/core/auditlogs/AuditLog.dart b/lib/src/core/auditlogs/AuditLog.dart similarity index 100% rename from nyxx/lib/src/core/auditlogs/AuditLog.dart rename to lib/src/core/auditlogs/AuditLog.dart diff --git a/nyxx/lib/src/core/auditlogs/AuditLogChange.dart b/lib/src/core/auditlogs/AuditLogChange.dart similarity index 100% rename from nyxx/lib/src/core/auditlogs/AuditLogChange.dart rename to lib/src/core/auditlogs/AuditLogChange.dart diff --git a/nyxx/lib/src/core/auditlogs/AuditLogEntry.dart b/lib/src/core/auditlogs/AuditLogEntry.dart similarity index 100% rename from nyxx/lib/src/core/auditlogs/AuditLogEntry.dart rename to lib/src/core/auditlogs/AuditLogEntry.dart diff --git a/nyxx/lib/src/core/channel/Channel.dart b/lib/src/core/channel/Channel.dart similarity index 100% rename from nyxx/lib/src/core/channel/Channel.dart rename to lib/src/core/channel/Channel.dart diff --git a/nyxx/lib/src/core/channel/DMChannel.dart b/lib/src/core/channel/DMChannel.dart similarity index 100% rename from nyxx/lib/src/core/channel/DMChannel.dart rename to lib/src/core/channel/DMChannel.dart diff --git a/nyxx/lib/src/core/channel/TextChannel.dart b/lib/src/core/channel/TextChannel.dart similarity index 100% rename from nyxx/lib/src/core/channel/TextChannel.dart rename to lib/src/core/channel/TextChannel.dart diff --git a/nyxx/lib/src/core/channel/ThreadChannel.dart b/lib/src/core/channel/ThreadChannel.dart similarity index 97% rename from nyxx/lib/src/core/channel/ThreadChannel.dart rename to lib/src/core/channel/ThreadChannel.dart index 272a3b719..a097a2e2e 100644 --- a/nyxx/lib/src/core/channel/ThreadChannel.dart +++ b/lib/src/core/channel/ThreadChannel.dart @@ -1,135 +1,135 @@ -part of nyxx; - -/// Member of [ThreadChannel] -class ThreadMember extends SnowflakeEntity { - /// Reference to client - INyxx client; - - /// Reference to [ThreadChannel] - late final CacheableTextChannel thread; - - /// When member joined thread - late final DateTime joinTimestamp; - - /// Any user-thread settings, currently only used for notifications - late final int flags; - - /// [ThreadMember]s [Guild] - final Cacheable guild; - - /// [Cacheable] of [User] - Cacheable get user => _UserCacheable(this.client, this.id); - - /// [Cacheable] of [Member] - Cacheable get member => _MemberCacheable(this.client, this.id, this.guild); - - ThreadMember._new(this.client, RawApiMap raw, this.guild): super(Snowflake(raw["user_id"])) { - this.thread = CacheableTextChannel._new(client, Snowflake(raw["id"])); - this.joinTimestamp = DateTime.parse(raw["join_timestamp"] as String); - this.flags = raw["flags"] as int; - } -} - -class ThreadChannel extends MinimalGuildChannel implements TextChannel { - Timer? _typing; - - /// Owner of the thread - late final Cacheable owner; - - /// Approximate message count - late final int messageCount; - - /// Approximate member count - late final int memberCount; - - /// True if thread is archived - late final bool archived; - - /// Date when thread was archived - late final DateTime archiveAt; - - /// Time after what thread will be archived - late final ThreadArchiveTime archiveAfter; - - /// Whether non-moderators can add other non-moderators to a thread; only available on private threads - late final bool invitable; - - @override - Future get fileUploadLimit async { - final guildInstance = await this.guild.getOrDownload(); - return guildInstance.fileUploadLimit; - } - - @override - late final MessageCache messageCache = MessageCache._new(client._options.messageCacheSize); - - ThreadChannel._new(INyxx client, RawApiMap raw, [Snowflake? guildId]) : super._new(client, raw) { - this.owner = new _MemberCacheable(client, Snowflake(raw["owner_id"]), this.guild); - - this.messageCount = raw["message_count"] as int; - this.memberCount = raw["member_count"] as int; - - final meta = raw["thread_metadata"]; - this.archived = meta["archived"] as bool; - this.archiveAt = DateTime.parse(meta["archive_timestamp"] as String); - this.archiveAfter = ThreadArchiveTime._new(meta["auto_archive_duration"] as int); - this.invitable = raw["invitable"] as bool? ?? false; - } - - /// Fetches from API current list of member that has access to that thread - Stream fetchMembers() => - client.httpEndpoints.getThreadMembers(this.id, this.guild.id); - - @override - Future bulkRemoveMessages(Iterable messages) => - client.httpEndpoints.bulkRemoveMessages(this.id, messages); - - @override - Stream downloadMessages({int limit = 50, Snowflake? after, Snowflake? around, Snowflake? before}) => - client.httpEndpoints.downloadMessages(this.id, limit: limit, after: after, around: around, before: before); - - @override - Future fetchMessage(Snowflake messageId) async { - final message = await client.httpEndpoints.fetchMessage(this.id, messageId); - - if(client._cacheOptions.messageCachePolicyLocation.http && client._cacheOptions.messageCachePolicy.canCache(message)) { - this.messageCache.put(message); - } - - return message; - } - @override - Message? getMessage(Snowflake id) => this.messageCache[id]; - - @override - Future sendMessage(MessageBuilder builder) => - client.httpEndpoints.sendMessage(this.id, builder); - - @override - Future startTyping() async => - client.httpEndpoints.triggerTyping(this.id); - - @override - void startTypingLoop() { - startTyping(); - this._typing = Timer.periodic(const Duration(seconds: 7), (Timer t) => startTyping()); - } - - @override - void stopTypingLoop() => this._typing?.cancel(); - - /// Leaves this thread channel - Future leaveThread() => client.httpEndpoints.leaveGuild(this.id); - - /// Removes [user] from [ThreadChannel] - Future removeThreadMember(SnowflakeEntity user) => - client.httpEndpoints.removeThreadMember(this.id, user.id); - - /// Adds [user] to [ThreadChannel] - Future addThreadMember(SnowflakeEntity user) => - client.httpEndpoints.addThreadMember(this.id, user.id); - - @override - Stream fetchPinnedMessages() => - client.httpEndpoints.fetchPinnedMessages(this.id); -} +part of nyxx; + +/// Member of [ThreadChannel] +class ThreadMember extends SnowflakeEntity { + /// Reference to client + INyxx client; + + /// Reference to [ThreadChannel] + late final CacheableTextChannel thread; + + /// When member joined thread + late final DateTime joinTimestamp; + + /// Any user-thread settings, currently only used for notifications + late final int flags; + + /// [ThreadMember]s [Guild] + final Cacheable guild; + + /// [Cacheable] of [User] + Cacheable get user => _UserCacheable(this.client, this.id); + + /// [Cacheable] of [Member] + Cacheable get member => _MemberCacheable(this.client, this.id, this.guild); + + ThreadMember._new(this.client, RawApiMap raw, this.guild): super(Snowflake(raw["user_id"])) { + this.thread = CacheableTextChannel._new(client, Snowflake(raw["id"])); + this.joinTimestamp = DateTime.parse(raw["join_timestamp"] as String); + this.flags = raw["flags"] as int; + } +} + +class ThreadChannel extends MinimalGuildChannel implements TextChannel { + Timer? _typing; + + /// Owner of the thread + late final Cacheable owner; + + /// Approximate message count + late final int messageCount; + + /// Approximate member count + late final int memberCount; + + /// True if thread is archived + late final bool archived; + + /// Date when thread was archived + late final DateTime archiveAt; + + /// Time after what thread will be archived + late final ThreadArchiveTime archiveAfter; + + /// Whether non-moderators can add other non-moderators to a thread; only available on private threads + late final bool invitable; + + @override + Future get fileUploadLimit async { + final guildInstance = await this.guild.getOrDownload(); + return guildInstance.fileUploadLimit; + } + + @override + late final MessageCache messageCache = MessageCache._new(client._options.messageCacheSize); + + ThreadChannel._new(INyxx client, RawApiMap raw, [Snowflake? guildId]) : super._new(client, raw) { + this.owner = new _MemberCacheable(client, Snowflake(raw["owner_id"]), this.guild); + + this.messageCount = raw["message_count"] as int; + this.memberCount = raw["member_count"] as int; + + final meta = raw["thread_metadata"]; + this.archived = meta["archived"] as bool; + this.archiveAt = DateTime.parse(meta["archive_timestamp"] as String); + this.archiveAfter = ThreadArchiveTime._new(meta["auto_archive_duration"] as int); + this.invitable = raw["invitable"] as bool? ?? false; + } + + /// Fetches from API current list of member that has access to that thread + Stream fetchMembers() => + client.httpEndpoints.getThreadMembers(this.id, this.guild.id); + + @override + Future bulkRemoveMessages(Iterable messages) => + client.httpEndpoints.bulkRemoveMessages(this.id, messages); + + @override + Stream downloadMessages({int limit = 50, Snowflake? after, Snowflake? around, Snowflake? before}) => + client.httpEndpoints.downloadMessages(this.id, limit: limit, after: after, around: around, before: before); + + @override + Future fetchMessage(Snowflake messageId) async { + final message = await client.httpEndpoints.fetchMessage(this.id, messageId); + + if(client._cacheOptions.messageCachePolicyLocation.http && client._cacheOptions.messageCachePolicy.canCache(message)) { + this.messageCache.put(message); + } + + return message; + } + @override + Message? getMessage(Snowflake id) => this.messageCache[id]; + + @override + Future sendMessage(MessageBuilder builder) => + client.httpEndpoints.sendMessage(this.id, builder); + + @override + Future startTyping() async => + client.httpEndpoints.triggerTyping(this.id); + + @override + void startTypingLoop() { + startTyping(); + this._typing = Timer.periodic(const Duration(seconds: 7), (Timer t) => startTyping()); + } + + @override + void stopTypingLoop() => this._typing?.cancel(); + + /// Leaves this thread channel + Future leaveThread() => client.httpEndpoints.leaveGuild(this.id); + + /// Removes [user] from [ThreadChannel] + Future removeThreadMember(SnowflakeEntity user) => + client.httpEndpoints.removeThreadMember(this.id, user.id); + + /// Adds [user] to [ThreadChannel] + Future addThreadMember(SnowflakeEntity user) => + client.httpEndpoints.addThreadMember(this.id, user.id); + + @override + Stream fetchPinnedMessages() => + client.httpEndpoints.fetchPinnedMessages(this.id); +} diff --git a/nyxx/lib/src/core/channel/ThreadPreviewChannel.dart b/lib/src/core/channel/ThreadPreviewChannel.dart similarity index 97% rename from nyxx/lib/src/core/channel/ThreadPreviewChannel.dart rename to lib/src/core/channel/ThreadPreviewChannel.dart index 7c23cf2cc..d524bda9c 100644 --- a/nyxx/lib/src/core/channel/ThreadPreviewChannel.dart +++ b/lib/src/core/channel/ThreadPreviewChannel.dart @@ -1,106 +1,106 @@ -part of nyxx; - -/// Given when a thread is created as only partial information is available. If you want the final channel use [getThreadChannel] -class ThreadPreviewChannel extends IChannel implements TextChannel { - Timer? _typing; - late final INyxx _client; - - /// Name of the channel - late final String name; - - /// Approximate message count - late final int messageCount; - - /// Approximate member count - late final int memberCount; - - /// Guild where the thread is located - late final Cacheable guild; - - /// The text channel where the thread was made - late final CacheableTextChannel parentChannel; - - /// Initial author of the thread - late final Cacheable owner; - - /// Preview of initial members - late final List> memberPreview; - - /// If the thread has been archived - late final bool archived; - - /// When the thread will be archived - late final DateTime archivedTime; - - /// How long till the thread is archived - late final ThreadArchiveTime archivedAfter; - - ThreadPreviewChannel._new(INyxx this._client, RawApiMap raw) : super._new(_client, raw) { - this.name = raw["name"] as String; - this.messageCount = raw["message_count"] as int; - this.memberCount = raw["member_count"] as int; - this.parentChannel = CacheableTextChannel._new(client, Snowflake(raw["parent_id"])); - this.guild = CacheUtility.createCacheableGuild(client, Snowflake(raw["guild_id"])); - this.owner = CacheUtility.createCacheableMember(client, Snowflake(raw["owner_id"]), this.guild); - this.memberPreview = []; - if(raw["member_ids_preview"] != null) { - for(final String id in raw["member_ids_preview"] as List) { - this.memberPreview.add(CacheUtility.createCacheableMember(client, Snowflake(id), this.guild)); - } - } - final metadata = raw["thread_metadata"] as RawApiMap; - - this.archived = metadata["archived"] as bool; - this.archivedTime = DateTime.parse(metadata["archive_timestamp"] as String); - this.archivedAfter = ThreadArchiveTime._new(metadata["auto_archive_duration"] as int); - } - - /// Get the actual thread channel from the preview - _ChannelCacheable getThreadChannel() => new _ChannelCacheable(_client, this.id); - - @override - Future bulkRemoveMessages(Iterable messages) => - client.httpEndpoints.bulkRemoveMessages(this.id, messages); - - @override - Stream downloadMessages({int limit = 50, Snowflake? after, Snowflake? around, Snowflake? before}) => - client.httpEndpoints.downloadMessages(this.id, limit: limit, after: after, around: around, before: before); - - @override - Future fetchMessage(Snowflake messageId) => - client.httpEndpoints.fetchMessage(this.id, messageId); - - @override - Message? getMessage(Snowflake id) => this.messageCache[id]; - - @override - Future sendMessage(MessageBuilder builder) => - client.httpEndpoints.sendMessage(this.id, builder); - - @override - Future get fileUploadLimit async { - final guildInstance = await this.guild.getOrDownload(); - - return guildInstance.fileUploadLimit; - } - - @override - late final MessageCache messageCache = MessageCache._new(0); - - @override - Future startTyping() async => - client.httpEndpoints.triggerTyping(this.id); - - @override - void startTypingLoop() { - startTyping(); - this._typing = Timer.periodic(const Duration(seconds: 7), (Timer t) => startTyping()); - } - - @override - void stopTypingLoop() => this._typing?.cancel(); - - @override - Stream fetchPinnedMessages() => - client.httpEndpoints.fetchPinnedMessages(this.id); -} +part of nyxx; + +/// Given when a thread is created as only partial information is available. If you want the final channel use [getThreadChannel] +class ThreadPreviewChannel extends IChannel implements TextChannel { + Timer? _typing; + late final INyxx _client; + + /// Name of the channel + late final String name; + + /// Approximate message count + late final int messageCount; + + /// Approximate member count + late final int memberCount; + + /// Guild where the thread is located + late final Cacheable guild; + + /// The text channel where the thread was made + late final CacheableTextChannel parentChannel; + + /// Initial author of the thread + late final Cacheable owner; + + /// Preview of initial members + late final List> memberPreview; + + /// If the thread has been archived + late final bool archived; + + /// When the thread will be archived + late final DateTime archivedTime; + + /// How long till the thread is archived + late final ThreadArchiveTime archivedAfter; + + ThreadPreviewChannel._new(INyxx this._client, RawApiMap raw) : super._new(_client, raw) { + this.name = raw["name"] as String; + this.messageCount = raw["message_count"] as int; + this.memberCount = raw["member_count"] as int; + this.parentChannel = CacheableTextChannel._new(client, Snowflake(raw["parent_id"])); + this.guild = CacheUtility.createCacheableGuild(client, Snowflake(raw["guild_id"])); + this.owner = CacheUtility.createCacheableMember(client, Snowflake(raw["owner_id"]), this.guild); + this.memberPreview = []; + if(raw["member_ids_preview"] != null) { + for(final String id in raw["member_ids_preview"] as List) { + this.memberPreview.add(CacheUtility.createCacheableMember(client, Snowflake(id), this.guild)); + } + } + final metadata = raw["thread_metadata"] as RawApiMap; + + this.archived = metadata["archived"] as bool; + this.archivedTime = DateTime.parse(metadata["archive_timestamp"] as String); + this.archivedAfter = ThreadArchiveTime._new(metadata["auto_archive_duration"] as int); + } + + /// Get the actual thread channel from the preview + _ChannelCacheable getThreadChannel() => new _ChannelCacheable(_client, this.id); + + @override + Future bulkRemoveMessages(Iterable messages) => + client.httpEndpoints.bulkRemoveMessages(this.id, messages); + + @override + Stream downloadMessages({int limit = 50, Snowflake? after, Snowflake? around, Snowflake? before}) => + client.httpEndpoints.downloadMessages(this.id, limit: limit, after: after, around: around, before: before); + + @override + Future fetchMessage(Snowflake messageId) => + client.httpEndpoints.fetchMessage(this.id, messageId); + + @override + Message? getMessage(Snowflake id) => this.messageCache[id]; + + @override + Future sendMessage(MessageBuilder builder) => + client.httpEndpoints.sendMessage(this.id, builder); + + @override + Future get fileUploadLimit async { + final guildInstance = await this.guild.getOrDownload(); + + return guildInstance.fileUploadLimit; + } + + @override + late final MessageCache messageCache = MessageCache._new(0); + + @override + Future startTyping() async => + client.httpEndpoints.triggerTyping(this.id); + + @override + void startTypingLoop() { + startTyping(); + this._typing = Timer.periodic(const Duration(seconds: 7), (Timer t) => startTyping()); + } + + @override + void stopTypingLoop() => this._typing?.cancel(); + + @override + Stream fetchPinnedMessages() => + client.httpEndpoints.fetchPinnedMessages(this.id); +} diff --git a/nyxx/lib/src/core/channel/guild/ActivityTypes.dart b/lib/src/core/channel/guild/ActivityTypes.dart similarity index 100% rename from nyxx/lib/src/core/channel/guild/ActivityTypes.dart rename to lib/src/core/channel/guild/ActivityTypes.dart diff --git a/nyxx/lib/src/core/channel/guild/CategoryGuildChannel.dart b/lib/src/core/channel/guild/CategoryGuildChannel.dart similarity index 100% rename from nyxx/lib/src/core/channel/guild/CategoryGuildChannel.dart rename to lib/src/core/channel/guild/CategoryGuildChannel.dart diff --git a/nyxx/lib/src/core/channel/guild/GuildChannel.dart b/lib/src/core/channel/guild/GuildChannel.dart similarity index 100% rename from nyxx/lib/src/core/channel/guild/GuildChannel.dart rename to lib/src/core/channel/guild/GuildChannel.dart diff --git a/nyxx/lib/src/core/channel/guild/TextGuildChannel.dart b/lib/src/core/channel/guild/TextGuildChannel.dart similarity index 100% rename from nyxx/lib/src/core/channel/guild/TextGuildChannel.dart rename to lib/src/core/channel/guild/TextGuildChannel.dart diff --git a/nyxx/lib/src/core/channel/guild/VoiceChannel.dart b/lib/src/core/channel/guild/VoiceChannel.dart similarity index 100% rename from nyxx/lib/src/core/channel/guild/VoiceChannel.dart rename to lib/src/core/channel/guild/VoiceChannel.dart diff --git a/nyxx/lib/src/core/embed/Embed.dart b/lib/src/core/embed/Embed.dart similarity index 100% rename from nyxx/lib/src/core/embed/Embed.dart rename to lib/src/core/embed/Embed.dart diff --git a/nyxx/lib/src/core/embed/EmbedAuthor.dart b/lib/src/core/embed/EmbedAuthor.dart similarity index 100% rename from nyxx/lib/src/core/embed/EmbedAuthor.dart rename to lib/src/core/embed/EmbedAuthor.dart diff --git a/nyxx/lib/src/core/embed/EmbedField.dart b/lib/src/core/embed/EmbedField.dart similarity index 100% rename from nyxx/lib/src/core/embed/EmbedField.dart rename to lib/src/core/embed/EmbedField.dart diff --git a/nyxx/lib/src/core/embed/EmbedFooter.dart b/lib/src/core/embed/EmbedFooter.dart similarity index 100% rename from nyxx/lib/src/core/embed/EmbedFooter.dart rename to lib/src/core/embed/EmbedFooter.dart diff --git a/nyxx/lib/src/core/embed/EmbedProvider.dart b/lib/src/core/embed/EmbedProvider.dart similarity index 100% rename from nyxx/lib/src/core/embed/EmbedProvider.dart rename to lib/src/core/embed/EmbedProvider.dart diff --git a/nyxx/lib/src/core/embed/EmbedThumbnail.dart b/lib/src/core/embed/EmbedThumbnail.dart similarity index 100% rename from nyxx/lib/src/core/embed/EmbedThumbnail.dart rename to lib/src/core/embed/EmbedThumbnail.dart diff --git a/nyxx/lib/src/core/embed/EmbedVideo.dart b/lib/src/core/embed/EmbedVideo.dart similarity index 100% rename from nyxx/lib/src/core/embed/EmbedVideo.dart rename to lib/src/core/embed/EmbedVideo.dart diff --git a/nyxx/lib/src/core/guild/Ban.dart b/lib/src/core/guild/Ban.dart similarity index 100% rename from nyxx/lib/src/core/guild/Ban.dart rename to lib/src/core/guild/Ban.dart diff --git a/nyxx/lib/src/core/guild/ClientUser.dart b/lib/src/core/guild/ClientUser.dart similarity index 100% rename from nyxx/lib/src/core/guild/ClientUser.dart rename to lib/src/core/guild/ClientUser.dart diff --git a/nyxx/lib/src/core/guild/Guild.dart b/lib/src/core/guild/Guild.dart similarity index 100% rename from nyxx/lib/src/core/guild/Guild.dart rename to lib/src/core/guild/Guild.dart diff --git a/nyxx/lib/src/core/guild/GuildFeature.dart b/lib/src/core/guild/GuildFeature.dart similarity index 100% rename from nyxx/lib/src/core/guild/GuildFeature.dart rename to lib/src/core/guild/GuildFeature.dart diff --git a/nyxx/lib/src/core/guild/GuildNsfwLevel.dart b/lib/src/core/guild/GuildNsfwLevel.dart similarity index 100% rename from nyxx/lib/src/core/guild/GuildNsfwLevel.dart rename to lib/src/core/guild/GuildNsfwLevel.dart diff --git a/nyxx/lib/src/core/guild/GuildPreview.dart b/lib/src/core/guild/GuildPreview.dart similarity index 100% rename from nyxx/lib/src/core/guild/GuildPreview.dart rename to lib/src/core/guild/GuildPreview.dart diff --git a/nyxx/lib/src/core/guild/PremiumTier.dart b/lib/src/core/guild/PremiumTier.dart similarity index 100% rename from nyxx/lib/src/core/guild/PremiumTier.dart rename to lib/src/core/guild/PremiumTier.dart diff --git a/nyxx/lib/src/core/guild/Role.dart b/lib/src/core/guild/Role.dart similarity index 100% rename from nyxx/lib/src/core/guild/Role.dart rename to lib/src/core/guild/Role.dart diff --git a/nyxx/lib/src/core/guild/Status.dart b/lib/src/core/guild/Status.dart similarity index 100% rename from nyxx/lib/src/core/guild/Status.dart rename to lib/src/core/guild/Status.dart diff --git a/nyxx/lib/src/core/guild/Webhook.dart b/lib/src/core/guild/Webhook.dart similarity index 100% rename from nyxx/lib/src/core/guild/Webhook.dart rename to lib/src/core/guild/Webhook.dart diff --git a/nyxx/lib/src/core/message/Attachment.dart b/lib/src/core/message/Attachment.dart similarity index 100% rename from nyxx/lib/src/core/message/Attachment.dart rename to lib/src/core/message/Attachment.dart diff --git a/nyxx/lib/src/core/message/Emoji.dart b/lib/src/core/message/Emoji.dart similarity index 100% rename from nyxx/lib/src/core/message/Emoji.dart rename to lib/src/core/message/Emoji.dart diff --git a/nyxx/lib/src/core/message/GuildEmoji.dart b/lib/src/core/message/GuildEmoji.dart similarity index 100% rename from nyxx/lib/src/core/message/GuildEmoji.dart rename to lib/src/core/message/GuildEmoji.dart diff --git a/nyxx/lib/src/core/message/Message.dart b/lib/src/core/message/Message.dart similarity index 100% rename from nyxx/lib/src/core/message/Message.dart rename to lib/src/core/message/Message.dart diff --git a/nyxx/lib/src/core/message/MessageFlags.dart b/lib/src/core/message/MessageFlags.dart similarity index 100% rename from nyxx/lib/src/core/message/MessageFlags.dart rename to lib/src/core/message/MessageFlags.dart diff --git a/nyxx/lib/src/core/message/MessageReference.dart b/lib/src/core/message/MessageReference.dart similarity index 100% rename from nyxx/lib/src/core/message/MessageReference.dart rename to lib/src/core/message/MessageReference.dart diff --git a/nyxx/lib/src/core/message/MessageTimeStamp.dart b/lib/src/core/message/MessageTimeStamp.dart similarity index 100% rename from nyxx/lib/src/core/message/MessageTimeStamp.dart rename to lib/src/core/message/MessageTimeStamp.dart diff --git a/nyxx/lib/src/core/message/MessageType.dart b/lib/src/core/message/MessageType.dart similarity index 100% rename from nyxx/lib/src/core/message/MessageType.dart rename to lib/src/core/message/MessageType.dart diff --git a/nyxx/lib/src/core/message/Reaction.dart b/lib/src/core/message/Reaction.dart similarity index 100% rename from nyxx/lib/src/core/message/Reaction.dart rename to lib/src/core/message/Reaction.dart diff --git a/nyxx/lib/src/core/message/ReferencedMessage.dart b/lib/src/core/message/ReferencedMessage.dart similarity index 100% rename from nyxx/lib/src/core/message/ReferencedMessage.dart rename to lib/src/core/message/ReferencedMessage.dart diff --git a/nyxx/lib/src/core/message/Sticker.dart b/lib/src/core/message/Sticker.dart similarity index 100% rename from nyxx/lib/src/core/message/Sticker.dart rename to lib/src/core/message/Sticker.dart diff --git a/nyxx/lib/src/core/message/UnicodeEmoji.dart b/lib/src/core/message/UnicodeEmoji.dart similarity index 100% rename from nyxx/lib/src/core/message/UnicodeEmoji.dart rename to lib/src/core/message/UnicodeEmoji.dart diff --git a/nyxx/lib/src/core/message/components/ComponentStyle.dart b/lib/src/core/message/components/ComponentStyle.dart similarity index 100% rename from nyxx/lib/src/core/message/components/ComponentStyle.dart rename to lib/src/core/message/components/ComponentStyle.dart diff --git a/nyxx/lib/src/core/message/components/MessageComponent.dart b/lib/src/core/message/components/MessageComponent.dart similarity index 100% rename from nyxx/lib/src/core/message/components/MessageComponent.dart rename to lib/src/core/message/components/MessageComponent.dart diff --git a/nyxx/lib/src/core/permissions/PermissionOverrides.dart b/lib/src/core/permissions/PermissionOverrides.dart similarity index 100% rename from nyxx/lib/src/core/permissions/PermissionOverrides.dart rename to lib/src/core/permissions/PermissionOverrides.dart diff --git a/nyxx/lib/src/core/permissions/Permissions.dart b/lib/src/core/permissions/Permissions.dart similarity index 100% rename from nyxx/lib/src/core/permissions/Permissions.dart rename to lib/src/core/permissions/Permissions.dart diff --git a/nyxx/lib/src/core/permissions/PermissionsConstants.dart b/lib/src/core/permissions/PermissionsConstants.dart similarity index 100% rename from nyxx/lib/src/core/permissions/PermissionsConstants.dart rename to lib/src/core/permissions/PermissionsConstants.dart diff --git a/nyxx/lib/src/core/user/Member.dart b/lib/src/core/user/Member.dart similarity index 100% rename from nyxx/lib/src/core/user/Member.dart rename to lib/src/core/user/Member.dart diff --git a/nyxx/lib/src/core/user/NitroType.dart b/lib/src/core/user/NitroType.dart similarity index 100% rename from nyxx/lib/src/core/user/NitroType.dart rename to lib/src/core/user/NitroType.dart diff --git a/nyxx/lib/src/core/user/Presence.dart b/lib/src/core/user/Presence.dart similarity index 100% rename from nyxx/lib/src/core/user/Presence.dart rename to lib/src/core/user/Presence.dart diff --git a/nyxx/lib/src/core/user/User.dart b/lib/src/core/user/User.dart similarity index 100% rename from nyxx/lib/src/core/user/User.dart rename to lib/src/core/user/User.dart diff --git a/nyxx/lib/src/core/user/UserFlags.dart b/lib/src/core/user/UserFlags.dart similarity index 100% rename from nyxx/lib/src/core/user/UserFlags.dart rename to lib/src/core/user/UserFlags.dart diff --git a/nyxx/lib/src/core/voice/VoiceRegion.dart b/lib/src/core/voice/VoiceRegion.dart similarity index 100% rename from nyxx/lib/src/core/voice/VoiceRegion.dart rename to lib/src/core/voice/VoiceRegion.dart diff --git a/nyxx/lib/src/core/voice/VoiceState.dart b/lib/src/core/voice/VoiceState.dart similarity index 100% rename from nyxx/lib/src/core/voice/VoiceState.dart rename to lib/src/core/voice/VoiceState.dart diff --git a/nyxx/lib/src/events/ChannelEvents.dart b/lib/src/events/ChannelEvents.dart similarity index 100% rename from nyxx/lib/src/events/ChannelEvents.dart rename to lib/src/events/ChannelEvents.dart diff --git a/nyxx/lib/src/events/DisconnectEvent.dart b/lib/src/events/DisconnectEvent.dart similarity index 100% rename from nyxx/lib/src/events/DisconnectEvent.dart rename to lib/src/events/DisconnectEvent.dart diff --git a/nyxx/lib/src/events/GuildEvents.dart b/lib/src/events/GuildEvents.dart similarity index 100% rename from nyxx/lib/src/events/GuildEvents.dart rename to lib/src/events/GuildEvents.dart diff --git a/nyxx/lib/src/events/HttpEvents.dart b/lib/src/events/HttpEvents.dart similarity index 100% rename from nyxx/lib/src/events/HttpEvents.dart rename to lib/src/events/HttpEvents.dart diff --git a/nyxx/lib/src/events/InviteEvents.dart b/lib/src/events/InviteEvents.dart similarity index 100% rename from nyxx/lib/src/events/InviteEvents.dart rename to lib/src/events/InviteEvents.dart diff --git a/nyxx/lib/src/events/MemberChunkEvent.dart b/lib/src/events/MemberChunkEvent.dart similarity index 100% rename from nyxx/lib/src/events/MemberChunkEvent.dart rename to lib/src/events/MemberChunkEvent.dart diff --git a/nyxx/lib/src/events/MessageEvents.dart b/lib/src/events/MessageEvents.dart similarity index 100% rename from nyxx/lib/src/events/MessageEvents.dart rename to lib/src/events/MessageEvents.dart diff --git a/nyxx/lib/src/events/PresenceUpdateEvent.dart b/lib/src/events/PresenceUpdateEvent.dart similarity index 100% rename from nyxx/lib/src/events/PresenceUpdateEvent.dart rename to lib/src/events/PresenceUpdateEvent.dart diff --git a/nyxx/lib/src/events/RatelimitEvent.dart b/lib/src/events/RatelimitEvent.dart similarity index 100% rename from nyxx/lib/src/events/RatelimitEvent.dart rename to lib/src/events/RatelimitEvent.dart diff --git a/nyxx/lib/src/events/RawEvent.dart b/lib/src/events/RawEvent.dart similarity index 100% rename from nyxx/lib/src/events/RawEvent.dart rename to lib/src/events/RawEvent.dart diff --git a/nyxx/lib/src/events/ReadyEvent.dart b/lib/src/events/ReadyEvent.dart similarity index 100% rename from nyxx/lib/src/events/ReadyEvent.dart rename to lib/src/events/ReadyEvent.dart diff --git a/nyxx/lib/src/events/ThreadCreateEvent.dart b/lib/src/events/ThreadCreateEvent.dart similarity index 96% rename from nyxx/lib/src/events/ThreadCreateEvent.dart rename to lib/src/events/ThreadCreateEvent.dart index 5407546ec..66163efd0 100644 --- a/nyxx/lib/src/events/ThreadCreateEvent.dart +++ b/lib/src/events/ThreadCreateEvent.dart @@ -1,15 +1,15 @@ -part of nyxx; - -/// Fired when a thread is created -class ThreadCreateEvent { - /// The thread that was just created - late final ThreadChannel thread; - - ThreadCreateEvent._new(RawApiMap raw, Nyxx client) { - this.thread = ThreadChannel._new(client, raw["d"] as RawApiMap); - - if (client._cacheOptions.channelCachePolicyLocation.event && client._cacheOptions.channelCachePolicy.canCache(this.thread)) { - client.channels[this.thread.id] = this.thread; - } - } -} +part of nyxx; + +/// Fired when a thread is created +class ThreadCreateEvent { + /// The thread that was just created + late final ThreadChannel thread; + + ThreadCreateEvent._new(RawApiMap raw, Nyxx client) { + this.thread = ThreadChannel._new(client, raw["d"] as RawApiMap); + + if (client._cacheOptions.channelCachePolicyLocation.event && client._cacheOptions.channelCachePolicy.canCache(this.thread)) { + client.channels[this.thread.id] = this.thread; + } + } +} diff --git a/nyxx/lib/src/events/ThreadDeletedEvent.dart b/lib/src/events/ThreadDeletedEvent.dart similarity index 97% rename from nyxx/lib/src/events/ThreadDeletedEvent.dart rename to lib/src/events/ThreadDeletedEvent.dart index 96e201675..0448bebb9 100644 --- a/nyxx/lib/src/events/ThreadDeletedEvent.dart +++ b/lib/src/events/ThreadDeletedEvent.dart @@ -1,21 +1,21 @@ -part of nyxx; - -/// Fired when a thread is created -class ThreadDeletedEvent { - /// Thread that was deleted - late final CacheableTextChannel thread; - - /// Channel where thread was located - late final CacheableTextChannel parent; - - /// Guild where event was generated - late final Cacheable guild; - - ThreadDeletedEvent._new(RawApiMap raw, Nyxx client) { - final data = raw["d"] as RawApiMap; - - this.thread = CacheableTextChannel._new(client, Snowflake(data["id"])); - this.parent = CacheableTextChannel._new(client, Snowflake(data["parent_id"])); - this.guild = _GuildCacheable(client, Snowflake(data["guild_id"])); - } -} +part of nyxx; + +/// Fired when a thread is created +class ThreadDeletedEvent { + /// Thread that was deleted + late final CacheableTextChannel thread; + + /// Channel where thread was located + late final CacheableTextChannel parent; + + /// Guild where event was generated + late final Cacheable guild; + + ThreadDeletedEvent._new(RawApiMap raw, Nyxx client) { + final data = raw["d"] as RawApiMap; + + this.thread = CacheableTextChannel._new(client, Snowflake(data["id"])); + this.parent = CacheableTextChannel._new(client, Snowflake(data["parent_id"])); + this.guild = _GuildCacheable(client, Snowflake(data["guild_id"])); + } +} diff --git a/nyxx/lib/src/events/ThreadMembersUpdateEvent.dart b/lib/src/events/ThreadMembersUpdateEvent.dart similarity index 97% rename from nyxx/lib/src/events/ThreadMembersUpdateEvent.dart rename to lib/src/events/ThreadMembersUpdateEvent.dart index 9a2b0c19e..a3f41f94f 100644 --- a/nyxx/lib/src/events/ThreadMembersUpdateEvent.dart +++ b/lib/src/events/ThreadMembersUpdateEvent.dart @@ -1,38 +1,38 @@ -part of nyxx; - -/// Fired when a thread has a member added/removed -class ThreadMembersUpdateEvent { - /// The thread that was updated - late final CacheableTextChannel thread; - - /// The guild it was updated in - late final Cacheable guild; - - /// The members that were added. Note that they are not cached - late final Iterable> addedMembers; - - /// The approximate number of members in the thread, capped at 50 - late final int approxMemberCount; - - /// Users who were removed from the thread - late final Iterable> removedUsers; - - ThreadMembersUpdateEvent._new(RawApiMap raw, Nyxx client) { - final data = raw["d"] as RawApiMap; - - this.thread = CacheableTextChannel._new(client, Snowflake(data["id"])); - this.guild = _GuildCacheable(client, Snowflake(data["guild_id"])); - - this.addedMembers = [ - if(data["added_members"] != null) - for(final memberData in data["added_members"] as List) - _MemberCacheable(client, Snowflake(memberData["user_id"]), this.guild) - ]; - - this.removedUsers = [ - if(data["removed_member_ids"] != null) - for(final removedUserId in data["removed_member_ids"]) - _UserCacheable(client, Snowflake(removedUserId)) - ]; - } -} +part of nyxx; + +/// Fired when a thread has a member added/removed +class ThreadMembersUpdateEvent { + /// The thread that was updated + late final CacheableTextChannel thread; + + /// The guild it was updated in + late final Cacheable guild; + + /// The members that were added. Note that they are not cached + late final Iterable> addedMembers; + + /// The approximate number of members in the thread, capped at 50 + late final int approxMemberCount; + + /// Users who were removed from the thread + late final Iterable> removedUsers; + + ThreadMembersUpdateEvent._new(RawApiMap raw, Nyxx client) { + final data = raw["d"] as RawApiMap; + + this.thread = CacheableTextChannel._new(client, Snowflake(data["id"])); + this.guild = _GuildCacheable(client, Snowflake(data["guild_id"])); + + this.addedMembers = [ + if(data["added_members"] != null) + for(final memberData in data["added_members"] as List) + _MemberCacheable(client, Snowflake(memberData["user_id"]), this.guild) + ]; + + this.removedUsers = [ + if(data["removed_member_ids"] != null) + for(final removedUserId in data["removed_member_ids"]) + _UserCacheable(client, Snowflake(removedUserId)) + ]; + } +} diff --git a/nyxx/lib/src/events/TypingEvent.dart b/lib/src/events/TypingEvent.dart similarity index 100% rename from nyxx/lib/src/events/TypingEvent.dart rename to lib/src/events/TypingEvent.dart diff --git a/nyxx/lib/src/events/UserUpdateEvent.dart b/lib/src/events/UserUpdateEvent.dart similarity index 100% rename from nyxx/lib/src/events/UserUpdateEvent.dart rename to lib/src/events/UserUpdateEvent.dart diff --git a/nyxx/lib/src/events/VoiceServerUpdateEvent.dart b/lib/src/events/VoiceServerUpdateEvent.dart similarity index 100% rename from nyxx/lib/src/events/VoiceServerUpdateEvent.dart rename to lib/src/events/VoiceServerUpdateEvent.dart diff --git a/nyxx/lib/src/events/VoiceStateUpdateEvent.dart b/lib/src/events/VoiceStateUpdateEvent.dart similarity index 100% rename from nyxx/lib/src/events/VoiceStateUpdateEvent.dart rename to lib/src/events/VoiceStateUpdateEvent.dart diff --git a/nyxx/lib/src/internal/Constants.dart b/lib/src/internal/Constants.dart similarity index 100% rename from nyxx/lib/src/internal/Constants.dart rename to lib/src/internal/Constants.dart diff --git a/nyxx/lib/src/internal/_ConnectionManager.dart b/lib/src/internal/_ConnectionManager.dart similarity index 100% rename from nyxx/lib/src/internal/_ConnectionManager.dart rename to lib/src/internal/_ConnectionManager.dart diff --git a/nyxx/lib/src/internal/_EventController.dart b/lib/src/internal/_EventController.dart similarity index 100% rename from nyxx/lib/src/internal/_EventController.dart rename to lib/src/internal/_EventController.dart diff --git a/nyxx/lib/src/internal/_HttpEndpoints.dart b/lib/src/internal/_HttpEndpoints.dart similarity index 100% rename from nyxx/lib/src/internal/_HttpEndpoints.dart rename to lib/src/internal/_HttpEndpoints.dart diff --git a/nyxx/lib/src/internal/cache/Cache.dart b/lib/src/internal/cache/Cache.dart similarity index 100% rename from nyxx/lib/src/internal/cache/Cache.dart rename to lib/src/internal/cache/Cache.dart diff --git a/nyxx/lib/src/internal/cache/CachePolicy.dart b/lib/src/internal/cache/CachePolicy.dart similarity index 100% rename from nyxx/lib/src/internal/cache/CachePolicy.dart rename to lib/src/internal/cache/CachePolicy.dart diff --git a/nyxx/lib/src/internal/cache/Cacheable.dart b/lib/src/internal/cache/Cacheable.dart similarity index 100% rename from nyxx/lib/src/internal/cache/Cacheable.dart rename to lib/src/internal/cache/Cacheable.dart diff --git a/nyxx/lib/src/internal/cache/ChannelCache.dart b/lib/src/internal/cache/ChannelCache.dart similarity index 100% rename from nyxx/lib/src/internal/cache/ChannelCache.dart rename to lib/src/internal/cache/ChannelCache.dart diff --git a/nyxx/lib/src/internal/cache/MessageCache.dart b/lib/src/internal/cache/MessageCache.dart similarity index 100% rename from nyxx/lib/src/internal/cache/MessageCache.dart rename to lib/src/internal/cache/MessageCache.dart diff --git a/nyxx/lib/src/internal/cache/_SnowflakeCache.dart b/lib/src/internal/cache/_SnowflakeCache.dart similarity index 100% rename from nyxx/lib/src/internal/cache/_SnowflakeCache.dart rename to lib/src/internal/cache/_SnowflakeCache.dart diff --git a/nyxx/lib/src/internal/exceptions/EmbedBuilderArgumentException.dart b/lib/src/internal/exceptions/EmbedBuilderArgumentException.dart similarity index 100% rename from nyxx/lib/src/internal/exceptions/EmbedBuilderArgumentException.dart rename to lib/src/internal/exceptions/EmbedBuilderArgumentException.dart diff --git a/nyxx/lib/src/internal/exceptions/HttpClientException.dart b/lib/src/internal/exceptions/HttpClientException.dart similarity index 100% rename from nyxx/lib/src/internal/exceptions/HttpClientException.dart rename to lib/src/internal/exceptions/HttpClientException.dart diff --git a/nyxx/lib/src/internal/exceptions/InvalidShardException.dart b/lib/src/internal/exceptions/InvalidShardException.dart similarity index 100% rename from nyxx/lib/src/internal/exceptions/InvalidShardException.dart rename to lib/src/internal/exceptions/InvalidShardException.dart diff --git a/nyxx/lib/src/internal/exceptions/InvalidSnowflakeException.dart b/lib/src/internal/exceptions/InvalidSnowflakeException.dart similarity index 100% rename from nyxx/lib/src/internal/exceptions/InvalidSnowflakeException.dart rename to lib/src/internal/exceptions/InvalidSnowflakeException.dart diff --git a/nyxx/lib/src/internal/exceptions/MissingTokenError.dart b/lib/src/internal/exceptions/MissingTokenError.dart similarity index 100% rename from nyxx/lib/src/internal/exceptions/MissingTokenError.dart rename to lib/src/internal/exceptions/MissingTokenError.dart diff --git a/nyxx/lib/src/internal/http/HttpBucket.dart b/lib/src/internal/http/HttpBucket.dart similarity index 100% rename from nyxx/lib/src/internal/http/HttpBucket.dart rename to lib/src/internal/http/HttpBucket.dart diff --git a/nyxx/lib/src/internal/http/HttpHandler.dart b/lib/src/internal/http/HttpHandler.dart similarity index 100% rename from nyxx/lib/src/internal/http/HttpHandler.dart rename to lib/src/internal/http/HttpHandler.dart diff --git a/nyxx/lib/src/internal/http/HttpRequest.dart b/lib/src/internal/http/HttpRequest.dart similarity index 100% rename from nyxx/lib/src/internal/http/HttpRequest.dart rename to lib/src/internal/http/HttpRequest.dart diff --git a/nyxx/lib/src/internal/http/HttpResponse.dart b/lib/src/internal/http/HttpResponse.dart similarity index 100% rename from nyxx/lib/src/internal/http/HttpResponse.dart rename to lib/src/internal/http/HttpResponse.dart diff --git a/nyxx/lib/src/internal/http/_HttpClient.dart b/lib/src/internal/http/_HttpClient.dart similarity index 100% rename from nyxx/lib/src/internal/http/_HttpClient.dart rename to lib/src/internal/http/_HttpClient.dart diff --git a/nyxx/lib/src/internal/interfaces/Convertable.dart b/lib/src/internal/interfaces/Convertable.dart similarity index 100% rename from nyxx/lib/src/internal/interfaces/Convertable.dart rename to lib/src/internal/interfaces/Convertable.dart diff --git a/nyxx/lib/src/internal/interfaces/Disposable.dart b/lib/src/internal/interfaces/Disposable.dart similarity index 100% rename from nyxx/lib/src/internal/interfaces/Disposable.dart rename to lib/src/internal/interfaces/Disposable.dart diff --git a/nyxx/lib/src/internal/interfaces/IMessageAuthor.dart b/lib/src/internal/interfaces/IMessageAuthor.dart similarity index 100% rename from nyxx/lib/src/internal/interfaces/IMessageAuthor.dart rename to lib/src/internal/interfaces/IMessageAuthor.dart diff --git a/nyxx/lib/src/internal/interfaces/ISend.dart b/lib/src/internal/interfaces/ISend.dart similarity index 100% rename from nyxx/lib/src/internal/interfaces/ISend.dart rename to lib/src/internal/interfaces/ISend.dart diff --git a/nyxx/lib/src/internal/interfaces/Mentionable.dart b/lib/src/internal/interfaces/Mentionable.dart similarity index 100% rename from nyxx/lib/src/internal/interfaces/Mentionable.dart rename to lib/src/internal/interfaces/Mentionable.dart diff --git a/nyxx/lib/src/internal/response_wrapper/ThreadListResultWrapper.dart b/lib/src/internal/response_wrapper/ThreadListResultWrapper.dart similarity index 100% rename from nyxx/lib/src/internal/response_wrapper/ThreadListResultWrapper.dart rename to lib/src/internal/response_wrapper/ThreadListResultWrapper.dart diff --git a/nyxx/lib/src/internal/shard/Shard.dart b/lib/src/internal/shard/Shard.dart similarity index 100% rename from nyxx/lib/src/internal/shard/Shard.dart rename to lib/src/internal/shard/Shard.dart diff --git a/nyxx/lib/src/internal/shard/ShardManager.dart b/lib/src/internal/shard/ShardManager.dart similarity index 100% rename from nyxx/lib/src/internal/shard/ShardManager.dart rename to lib/src/internal/shard/ShardManager.dart diff --git a/nyxx/lib/src/internal/shard/shardHandler.dart b/lib/src/internal/shard/shardHandler.dart similarity index 100% rename from nyxx/lib/src/internal/shard/shardHandler.dart rename to lib/src/internal/shard/shardHandler.dart diff --git a/nyxx/lib/src/utils/BuilderUtility.dart b/lib/src/utils/BuilderUtility.dart similarity index 100% rename from nyxx/lib/src/utils/BuilderUtility.dart rename to lib/src/utils/BuilderUtility.dart diff --git a/nyxx/lib/src/utils/CacheUtility.dart b/lib/src/utils/CacheUtility.dart similarity index 100% rename from nyxx/lib/src/utils/CacheUtility.dart rename to lib/src/utils/CacheUtility.dart diff --git a/nyxx/lib/src/utils/EntityUtility.dart b/lib/src/utils/EntityUtility.dart similarity index 100% rename from nyxx/lib/src/utils/EntityUtility.dart rename to lib/src/utils/EntityUtility.dart diff --git a/nyxx/lib/src/utils/IEnum.dart b/lib/src/utils/IEnum.dart similarity index 100% rename from nyxx/lib/src/utils/IEnum.dart rename to lib/src/utils/IEnum.dart diff --git a/nyxx/lib/src/utils/builders/AttachmentBuilder.dart b/lib/src/utils/builders/AttachmentBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/AttachmentBuilder.dart rename to lib/src/utils/builders/AttachmentBuilder.dart diff --git a/nyxx/lib/src/utils/builders/Builder.dart b/lib/src/utils/builders/Builder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/Builder.dart rename to lib/src/utils/builders/Builder.dart diff --git a/nyxx/lib/src/utils/builders/EmbedAuthorBuilder.dart b/lib/src/utils/builders/EmbedAuthorBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/EmbedAuthorBuilder.dart rename to lib/src/utils/builders/EmbedAuthorBuilder.dart diff --git a/nyxx/lib/src/utils/builders/EmbedBuilder.dart b/lib/src/utils/builders/EmbedBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/EmbedBuilder.dart rename to lib/src/utils/builders/EmbedBuilder.dart diff --git a/nyxx/lib/src/utils/builders/EmbedFieldBuilder.dart b/lib/src/utils/builders/EmbedFieldBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/EmbedFieldBuilder.dart rename to lib/src/utils/builders/EmbedFieldBuilder.dart diff --git a/nyxx/lib/src/utils/builders/EmbedFooterBuilder.dart b/lib/src/utils/builders/EmbedFooterBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/EmbedFooterBuilder.dart rename to lib/src/utils/builders/EmbedFooterBuilder.dart diff --git a/nyxx/lib/src/utils/builders/GuildBuilder.dart b/lib/src/utils/builders/GuildBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/GuildBuilder.dart rename to lib/src/utils/builders/GuildBuilder.dart diff --git a/nyxx/lib/src/utils/builders/MessageBuilder.dart b/lib/src/utils/builders/MessageBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/MessageBuilder.dart rename to lib/src/utils/builders/MessageBuilder.dart diff --git a/nyxx/lib/src/utils/builders/PermissionsBuilder.dart b/lib/src/utils/builders/PermissionsBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/PermissionsBuilder.dart rename to lib/src/utils/builders/PermissionsBuilder.dart diff --git a/nyxx/lib/src/utils/builders/PresenceBuilder.dart b/lib/src/utils/builders/PresenceBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/PresenceBuilder.dart rename to lib/src/utils/builders/PresenceBuilder.dart diff --git a/nyxx/lib/src/utils/builders/ReplyBuilder.dart b/lib/src/utils/builders/ReplyBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/ReplyBuilder.dart rename to lib/src/utils/builders/ReplyBuilder.dart diff --git a/nyxx/lib/src/utils/builders/StickerBuilder.dart b/lib/src/utils/builders/StickerBuilder.dart similarity index 100% rename from nyxx/lib/src/utils/builders/StickerBuilder.dart rename to lib/src/utils/builders/StickerBuilder.dart diff --git a/nyxx/lib/src/utils/builders/ThreadBuilder.dart b/lib/src/utils/builders/ThreadBuilder.dart similarity index 96% rename from nyxx/lib/src/utils/builders/ThreadBuilder.dart rename to lib/src/utils/builders/ThreadBuilder.dart index 636407656..797348256 100644 --- a/nyxx/lib/src/utils/builders/ThreadBuilder.dart +++ b/lib/src/utils/builders/ThreadBuilder.dart @@ -1,57 +1,57 @@ -part of nyxx; - -class ThreadBuilder extends Builder { - - /// The name fo the thread - String? name; - - /// Whether or not the thread is private - bool private = false; - - /// The time after which the thread is automatically archived. - ThreadArchiveTime archiveAfter = ThreadArchiveTime.day; - - /// Create a public thread - ThreadBuilder(this.name); - - /// Create a private thread - ThreadBuilder.private(this.name) { - this.private = true; - } - - /// Set the time after which the thread automatically archives itself. - void setArchiveAfter(ThreadArchiveTime time) => this.archiveAfter = time; - - /// Make the thread private - void setPrivate() => this.private = true; - - /// Make the thread public - void setPublic() => this.private = false; - - @override - RawApiMap build() => { - "auto_archive_duration": this.archiveAfter.value, - "name": name, - "type": private ? 12 : 11 - }; -} - -/// Simplifies the process of setting an auto archive time. -class ThreadArchiveTime extends IEnum { - const ThreadArchiveTime._new(int value) : super(value); - - /// Archive after an hour - static const ThreadArchiveTime hour = ThreadArchiveTime._new(60); - - /// Archive after an day - static const ThreadArchiveTime day = ThreadArchiveTime._new(1440); - - /// Archive after 3 days - static const ThreadArchiveTime threeDays = ThreadArchiveTime._new(4320); - - /// Archive after an week - static const ThreadArchiveTime week = ThreadArchiveTime._new(10080); - - @override - String toString() => _value.toString(); -} +part of nyxx; + +class ThreadBuilder extends Builder { + + /// The name fo the thread + String? name; + + /// Whether or not the thread is private + bool private = false; + + /// The time after which the thread is automatically archived. + ThreadArchiveTime archiveAfter = ThreadArchiveTime.day; + + /// Create a public thread + ThreadBuilder(this.name); + + /// Create a private thread + ThreadBuilder.private(this.name) { + this.private = true; + } + + /// Set the time after which the thread automatically archives itself. + void setArchiveAfter(ThreadArchiveTime time) => this.archiveAfter = time; + + /// Make the thread private + void setPrivate() => this.private = true; + + /// Make the thread public + void setPublic() => this.private = false; + + @override + RawApiMap build() => { + "auto_archive_duration": this.archiveAfter.value, + "name": name, + "type": private ? 12 : 11 + }; +} + +/// Simplifies the process of setting an auto archive time. +class ThreadArchiveTime extends IEnum { + const ThreadArchiveTime._new(int value) : super(value); + + /// Archive after an hour + static const ThreadArchiveTime hour = ThreadArchiveTime._new(60); + + /// Archive after an day + static const ThreadArchiveTime day = ThreadArchiveTime._new(1440); + + /// Archive after 3 days + static const ThreadArchiveTime threeDays = ThreadArchiveTime._new(4320); + + /// Archive after an week + static const ThreadArchiveTime week = ThreadArchiveTime._new(10080); + + @override + String toString() => _value.toString(); +} diff --git a/nyxx/lib/src/utils/extensions.dart b/lib/src/utils/extensions.dart similarity index 100% rename from nyxx/lib/src/utils/extensions.dart rename to lib/src/utils/extensions.dart diff --git a/nyxx/lib/src/utils/permissions.dart b/lib/src/utils/permissions.dart similarity index 100% rename from nyxx/lib/src/utils/permissions.dart rename to lib/src/utils/permissions.dart diff --git a/nyxx/lib/src/utils/utils.dart b/lib/src/utils/utils.dart similarity index 100% rename from nyxx/lib/src/utils/utils.dart rename to lib/src/utils/utils.dart diff --git a/nyxx/LICENSE b/nyxx/LICENSE deleted file mode 100644 index 1dfc579d0..000000000 --- a/nyxx/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 Szymon Uglis, Harry Bairstow and contributors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/nyxx/README.md b/nyxx/README.md deleted file mode 100644 index d8553f02a..000000000 --- a/nyxx/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# nyxx - -[![pub](https://img.shields.io/pub/v/nyxx.svg)](https://pub.dartlang.org/packages/nyxx) -[![documentation](https://img.shields.io/badge/Documentation-nyxx-yellow.svg)](https://www.dartdocs.org/documentation/nyxx/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.commander-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.commander/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.interactions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.interactions/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.extentions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.extensions/latest/) - -Simple, robust framework for creating discord bots for Dart language. - -
- -### Features - -- **Slash commands support**
- Supports and provides easy API for creating and handling slash commands -- **Commands framework included**
- A fast way to create a bot with command support. Implementing the framework is simple - and everything is done automatically. -- **Cross Platform**
- Nyxx works on the command line, in the browser, and on mobile devices. -- **Fine Control**
- Nyxx allows you to control every outgoing HTTP request or WebSocket message. -- **Complete**
- Nyxx supports nearly all Discord API endpoints. - - -## Quick example - -Basic usage: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - bot.onMessageReceived.listen((event) { - if (event.message.content == "!ping") { - event.message.channel.getFromCache()?.sendMessage(content: "Pong!"); - } - }); -} -``` - -Slash commands: -```dart -void main() { - final bot = Nyxx("<%TOKEN%>", GatewayIntents.allUnprivileged); - Interactions(bot) - ..registerSlashCommand( - SlashCommandBuilder("hi", "This is example slash command", []) - ..registerHandler((event) async { - await event.acknowledge(); - - await event.respond(MessageBuilder.content("Hello World!")); - }) - ); -} -``` - -Commands: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - Commander(bot, prefix: "!!!") - ..registerCommand("ping", (context, message) => context.reply(content: "Pong!")); -} -``` - -## More examples - -Nyxx examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx/example). - -Commander examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx.commander/example) - -Slash commands (interactions) examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx.interactions/example) - -### Example bots -- [Running on Dart](https://github.com/l7ssha/running_on_dart) - -## Documentation, help and examples - -**Dartdoc documentation is hosted on [pub](https://www.dartdocs.org/documentation/nyxx/latest/). -This wiki just fills gap in docs with more descriptive guides and tutorials.** - -#### [Discord API docs](https://discordapp.com/developers/docs/intro) -Discord API documentation features rich descriptions about all topics that nyxx covers. - -#### [Discord API Guild](https://discord.gg/discord-api) -The unofficial guild for Discord Bot developers. To get help with nyxx check `#dart_nyxx` channel. - -#### [Dartdocs](https://www.dartdocs.org/documentation/nyxx/latest/) -The dartdocs page will always have the documentation for the latest release. - -#### [Dev docs](https://nyxx.l7ssha.xyz) -You can read about upcoming changes in the library on my website. - -#### [Wiki](https://github.com/l7ssha/nyxx/wiki) -Wiki documentation are designed to match the latest Nyxx release. - -## Contributing to Nyxx - -Read [contributing document](https://github.com/l7ssha/nyxx/blob/development/CONTRIBUTING.md) - -## Credits - -* [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx). diff --git a/nyxx_commander/CHANGELOG.md b/nyxx_commander/CHANGELOG.md deleted file mode 100644 index 60fb5cd72..000000000 --- a/nyxx_commander/CHANGELOG.md +++ /dev/null @@ -1,42 +0,0 @@ -## 2.0.1 -_15.10.2021_ - -- Move to Apache 2 license - -## 2.0.0 -_03.10.2021_ - -> Bumped version to 2.0 for compatibility with nyxx - -- Support for aliases for Commander (580e55c) -- Fix command aliases (17187c5) @WasserEsser -- Fix command recognition in Commander (7fff136) @WasserEsser - -## 2.0.0-rc.3 -_25.04.2021_ - -> **Release Candidate 2 for stable version. Requires dart sdk 2.12** - -- Support for aliases for Commander (580e55c) -- Fix command aliases (17187c5) @WasserEsser -- Fix command recognition in Commander (7fff136) @WasserEsser - -## 1.0.1 -_03.09.2020_ - -* Fix default command handler not being invoked. - -## 1.0.0 -_24.08.2020_ - -> **Stable release - breaks with previous versions - this version required Dart 2.9 stable and non-nullable experiment to be enabled to function** - -> **`1.0.0` drops support for browser. Nyxx will now run only on VM** - -* `dart:mirrors` no longer required to function -* Support for command and command groups -* Allows to run code before and after invoking command. Allows to run code before matching command. -* Fixed and added new functionality to `CommandContext` - - Support for extracting quoted text, parameters and code blocks - - Getter for shard that command is executed -* Improved performance and extensibility diff --git a/nyxx_commander/LICENSE b/nyxx_commander/LICENSE deleted file mode 100644 index 1dfc579d0..000000000 --- a/nyxx_commander/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 Szymon Uglis, Harry Bairstow and contributors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/nyxx_commander/README.md b/nyxx_commander/README.md deleted file mode 100644 index 16479055d..000000000 --- a/nyxx_commander/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# nyxx_commander - -[![pub](https://img.shields.io/pub/v/nyxx.svg)](https://pub.dartlang.org/packages/nyxx) -[![documentation](https://img.shields.io/badge/Documentation-nyxx-yellow.svg)](https://www.dartdocs.org/documentation/nyxx/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.commander-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.commander/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.interactions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.interactions/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.extentions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.extensions/latest/) - -Simple, robust framework for creating discord bots for Dart language. - -
- -### Features - -- **Slash commands support**
- Supports and provides easy API for creating and handling slash commands -- **Commands framework included**
- A fast way to create a bot with command support. Implementing the framework is simple - and everything is done automatically. -- **Cross Platform**
- Nyxx works on the command line, in the browser, and on mobile devices. -- **Fine Control**
- Nyxx allows you to control every outgoing HTTP request or WebSocket message. -- **Complete**
- Nyxx supports nearly all Discord API endpoints. - - -## Quick example - -Basic usage: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - bot.onMessageReceived.listen((event) { - if (event.message.content == "!ping") { - event.message.channel.getFromCache()?.sendMessage(content: "Pong!"); - } - }); -} -``` - -Slash commands: -```dart -void main() { - final bot = Nyxx("<%TOKEN%>", GatewayIntents.allUnprivileged); - Interactions(bot) - ..registerSlashCommand( - SlashCommandBuilder("hi", "This is example slash command", []) - ..registerHandler((event) async { - await event.acknowledge(); - - await event.respond(MessageBuilder.content("Hello World!")); - }) - ); -} -``` - -Commands: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - Commander(bot, prefix: "!!!") - ..registerCommand("ping", (context, message) => context.reply(content: "Pong!")); -} -``` - -## More examples - -Nyxx examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx/example). - -Commander examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx.commander/example) - -Slash commands (interactions) examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx.interactions/example) - -### Example bots -- [Running on Dart](https://github.com/l7ssha/running_on_dart) - -## Documentation, help and examples - -**Dartdoc documentation is hosted on [pub](https://www.dartdocs.org/documentation/nyxx/latest/). -This wiki just fills gap in docs with more descriptive guides and tutorials.** - -#### [Discord API docs](https://discordapp.com/developers/docs/intro) -Discord API documentation features rich descriptions about all topics that nyxx covers. - -#### [Discord API Guild](https://discord.gg/discord-api) -The unofficial guild for Discord Bot developers. To get help with nyxx check `#dart_nyxx` channel. - -#### [Dartdocs](https://www.dartdocs.org/documentation/nyxx/latest/) -The dartdocs page will always have the documentation for the latest release. - -#### [Dev docs](https://nyxx.l7ssha.xyz) -You can read about upcoming changes in the library on my website. - -#### [Wiki](https://github.com/l7ssha/nyxx/wiki) -Wiki documentation are designed to match the latest Nyxx release. - -## Contributing to Nyxx - -Read [contributing document](https://github.com/l7ssha/nyxx/blob/development/CONTRIBUTING.md) - -## Credits - -* [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx). diff --git a/nyxx_commander/analysis_options.yaml b/nyxx_commander/analysis_options.yaml deleted file mode 100644 index 5f62d3846..000000000 --- a/nyxx_commander/analysis_options.yaml +++ /dev/null @@ -1,107 +0,0 @@ -analyzer: - strong-mode: - implicit-casts: false -linter: - rules: - - avoid_empty_else - - comment_references - - control_flow_in_finally - - empty_statements - - hash_and_equals - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - avoid_slow_async_io - - cancel_subscriptions - - test_types_in_equals - - throw_in_finally - - valid_regexps - - always_declare_return_types - - annotate_overrides - - avoid_init_to_null - - avoid_return_types_on_setters - - await_only_futures - - camel_case_types - - constant_identifier_names - - empty_constructor_bodies - - library_names - - library_prefixes - - non_constant_identifier_names - - only_throw_errors - - package_api_docs - - package_prefixed_library_names - - prefer_is_not_empty - - slash_for_doc_comments - - type_init_formals - - unnecessary_getters_setters - - package_names - - unnecessary_await_in_return - - use_function_type_syntax_for_parameters - - avoid_returning_null_for_future - - no_duplicate_case_values - - unnecessary_statements - - always_require_non_null_named_parameters - - always_put_required_named_parameters_first - - avoid_catches_without_on_clauses - - avoid_function_literals_in_foreach_calls - - avoid_redundant_argument_values - - avoid_returning_null - - avoid_returning_null_for_void - - avoid_returning_this - - camel_case_extensions - - curly_braces_in_flow_control_structures - - directives_ordering - - empty_catches - - join_return_with_assignment - - leading_newlines_in_multiline_strings - - missing_whitespace_between_adjacent_strings - - no_runtimeType_toString - - null_closures - - omit_local_variable_types - - one_member_abstracts - - prefer_adjacent_string_concatenation - - prefer_collection_literals - - prefer_conditional_assignment - - prefer_const_constructors - - prefer_const_constructors_in_immutables - - prefer_const_declarations - - prefer_const_literals_to_create_immutables - - prefer_constructors_over_static_methods - - prefer_contains - - prefer_double_quotes - - prefer_equal_for_default_values - - prefer_expression_function_bodies - - prefer_final_fields - - prefer_final_in_for_each - - prefer_final_locals - - prefer_for_elements_to_map_fromIterable - - prefer_foreach - - prefer_function_declarations_over_variables - - prefer_generic_function_type_aliases - - prefer_if_elements_to_conditional_expressions - - prefer_if_null_operators - - prefer_initializing_formals - - prefer_inlined_adds - - prefer_int_literals - - prefer_interpolation_to_compose_strings - - prefer_is_empty - - provide_deprecation_message - - prefer_typing_uninitialized_variables - - public_member_api_docs - - type_annotate_public_apis - - unawaited_futures - - unnecessary_brace_in_string_interps - - unnecessary_lambdas - - unnecessary_null_in_if_null_operators - - unnecessary_parenthesis - - unnecessary_raw_strings - - unnecessary_string_escapes - - use_rethrow_when_possible - - use_string_buffers - - void_checks - - use_to_and_as_if_applicable - - sort_pub_dependencies - - prefer_is_not_operator - - prefer_iterable_whereType - - prefer_mixin - - prefer_null_aware_operators - - prefer_spread_collections diff --git a/nyxx_commander/example/example.dart b/nyxx_commander/example/example.dart deleted file mode 100644 index 862ba0394..000000000 --- a/nyxx_commander/example/example.dart +++ /dev/null @@ -1,13 +0,0 @@ -import "package:nyxx/nyxx.dart"; -import "package:nyxx_commander/commander.dart"; - -void main() { - // Start bot - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - // Start commander with prefix `!` - Commander(bot, prefix: "!") - ..registerCommand("ping", (context, message) { // register command ping that will answer pong - context.reply(MessageBuilder.content("Pong")); - }); -} diff --git a/nyxx_commander/example/per_guild_prefix.dart b/nyxx_commander/example/per_guild_prefix.dart deleted file mode 100644 index d105cda51..000000000 --- a/nyxx_commander/example/per_guild_prefix.dart +++ /dev/null @@ -1,55 +0,0 @@ -import "dart:async"; - -import "package:nyxx/nyxx.dart"; -import "package:nyxx_commander/commander.dart"; - -// Temporary storage for prefixes per guild -// Note that this implementation is just proof of concept -// and in production you should use some kind of database to store data -final prefixes = {}; - -const defaultPrefix = "!"; - -FutureOr prefixHandler(Message message) { - // Check if we are in DMs, if true then return default prefix - if (message is DMMessage) { - return defaultPrefix; - } - - final guildMessage = message as GuildMessage; // case message to GuildMessage since we are sure we are not in DMs - final prefixForGuild = prefixes[guildMessage.guild.id]; // Get prefix for guild id. Will return null if not present - - return prefixForGuild ?? defaultPrefix; // return prefix for guild if not null or default prefix otherwise -} - -void main() { - // Start bot - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - // Start commander with prefix `!` - Commander(bot, prefixHandler: prefixHandler) // prefixHandler will handle deciding which guild can use which prefix - ..registerCommand("ping", (context, message) { // register command ping that will answer pong - context.reply(MessageBuilder.content("Pong")); - }) - ..registerCommand("setPrefix", (context, message) { - // Check if message was sent in DMs - if (context.guild == null) { - context.reply(MessageBuilder.content("Cannot set prefix in DMs")); - return; - } - - final args = context.getArguments(); // Context#getArguments will return stuff after prefix and command name. - - // Check if user passed any arguments to command - if (args.isEmpty) { - context.reply(MessageBuilder.content("After command name there has to be desired prefix you want to set")); - return; - } - - // Since we care only about prefix we are using .first to take first element - // and set given prefix for guild - prefixes[context.guild!.id] = args.first; - - context.reply(MessageBuilder.content("Prefix set to `${args.first}` successfully!")); - }); -} diff --git a/nyxx_commander/lib/commander.dart b/nyxx_commander/lib/commander.dart deleted file mode 100644 index 57476ebcc..000000000 --- a/nyxx_commander/lib/commander.dart +++ /dev/null @@ -1,14 +0,0 @@ -library nyxx_commander; - -import "dart:async"; -import "dart:io"; - -import "package:logging/logging.dart"; - -import "package:nyxx/nyxx.dart"; - -part "src/Commander.dart"; -part "src/CommandContext.dart"; -part "src/CommandHandler.dart"; - -part "src/utils.dart"; diff --git a/nyxx_commander/lib/src/CommandContext.dart b/nyxx_commander/lib/src/CommandContext.dart deleted file mode 100644 index c4ecd4f3c..000000000 --- a/nyxx_commander/lib/src/CommandContext.dart +++ /dev/null @@ -1,196 +0,0 @@ -part of nyxx_commander; - -/// Helper class which describes context in which command is executed -class CommandContext { - /// Channel from where message come from - final TextChannel channel; - - /// Author of message - final IMessageAuthor author; - - /// Message that was sent - final Message message; - - /// Guild in which message was sent - final Guild? guild; - - /// Returns author as guild member - Member? get member => this.message is GuildMessage - ? (message as GuildMessage).member - : null; - - /// Reference to client - Nyxx get client => channel.client as Nyxx; - - /// Shard on which message was sent - int get shardId => this.guild != null ? this.guild!.shard.id : 0; - - /// Substring by which command was matched - final String commandMatcher; - - CommandContext._new(this.channel, this.author, this.guild, this.message, this.commandMatcher); - - static final _argumentsRegex = RegExp('([^"\' ]+)|["\']([^"]*)["\']'); - static final _quotedTextRegex = RegExp('["\']([^"]*)["\']'); - static final _codeBlocksRegex = RegExp(r"```(\w+)?(\s)?(((.+)(\s)?)+)```"); - - /// Creates inline reply for message - Future reply(MessageBuilder builder, {bool mention = false, bool reply = false }) async { - if (mention) { - if (builder.allowedMentions != null) { - builder.allowedMentions!.allow(reply: true); - } else { - builder.allowedMentions = AllowedMentions()..allow(reply: true); - } - } - - if (reply) { - builder.replyBuilder = ReplyBuilder.fromMessage(this.message); - } - - return channel.sendMessage(builder); - } - - /// Reply to message. It allows to send regular message, Embed or both. - /// - /// ``` - /// Future getAv(CommandContext context) async { - /// await context.reply(content: context.user.avatarURL()); - /// } - /// ``` - Future sendMessage(MessageBuilder builder) => channel.sendMessage(builder); - - /// Reply to messages, then delete it when [duration] expires. - /// - /// ``` - /// Future getAv(CommandContext context) async { - /// await context.replyTemp(content: user.avatarURL()); - /// } - /// ``` - Future sendMessageTemp(Duration duration, MessageBuilder builder) => channel - .sendMessage(builder) - .then((msg) { - Timer(duration, () => msg.delete()); - return msg; - }); - - /// Replies to message after delay specified with [duration] - /// ``` - /// Future getAv(CommandContext context async { - /// await context.replyDelayed(Duration(seconds: 2), content: user.avatarURL()); - /// } - /// ``` - Future sendMessageDelayed(Duration duration, MessageBuilder builder) => - Future.delayed(duration, () => channel.sendMessage(builder)); - - /// Awaits for emoji under given [msg] - Future awaitEmoji(Message msg) async => - (await this.client.onMessageReactionAdded.where((event) => event.message == msg).first).emoji; - - /// Collects emojis within given [duration]. Returns empty map if no reaction received - /// - /// ``` - /// Future getAv(CommandContext context) async { - /// final msg = await context.replyDelayed(content: context.user.avatarURL()); - /// final emojis = await context.awaitEmojis(msg, Duration(seconds: 15)); - /// - /// } - /// ``` - Future> awaitEmojis(Message msg, Duration duration){ - final collectedEmoji = {}; - return Future>(() async { - await for (final event in client.onMessageReactionAdded.where((evnt) => evnt.message != null && evnt.message!.id == msg.id)) { - if (collectedEmoji.containsKey(event.emoji)) { - // TODO: NNBD: weird stuff - var value = collectedEmoji[event.emoji]; - - if (value != null) { - value += 1; - collectedEmoji[event.emoji] = value; - } - } else { - collectedEmoji[event.emoji] = 1; - } - } - - return collectedEmoji; - }).timeout(duration, onTimeout: () => collectedEmoji); - } - - - /// Waits for first [TypingEvent] and returns it. If timed out returns null. - /// Can listen to specific user by specifying [user] - Future waitForTyping(User user, {Duration timeout = const Duration(seconds: 30)}) => - Future(() => client.onTyping.firstWhere((e) => e.user == user && e.channel == this.channel)).timeout(timeout, onTimeout: () => null); - - /// Gets all context channel messages that satisfies [predicate]. - /// - /// ``` - /// Future getAv(CommandContext context) async { - /// final messages = await context.nextMessagesWhere((msg) => msg.content.startsWith("fuck")); - /// } - /// ``` - Stream nextMessagesWhere(bool Function(MessageReceivedEvent msg) predicate, {int limit = 1}) => - client.onMessageReceived.where((event) => event.message.channel.id == channel.id).where(predicate).take(limit); - - /// Gets next [num] number of any messages sent within one context (same channel). - /// - /// ``` - /// Future getAv(CommandContext context) async { - /// // gets next 10 messages - /// final messages = await context.nextMessages(10); - /// } - /// ``` - Stream nextMessages(int num) => - client.onMessageReceived.where((event) => event.message.channel.id == channel.id).take(num); - - /// Starts typing loop and ends when [callback] resolves. - Future enterTypingState(Future Function() callback) async { - this.channel.startTypingLoop(); - final result = await callback(); - this.channel.stopTypingLoop(); - - return result; - } - - /// Returns list of words separated with space and/or text surrounded by quotes - /// Text: `hi this is "example stuff" which 'can be parsed'` will return - /// `List [hi, this, is, example stuff, which, can be parsed]` - Iterable getArguments() sync* { - final matches = _argumentsRegex.allMatches(this.message.content.toLowerCase().replaceFirst(commandMatcher.toLowerCase(), "")); - - for(final match in matches) { - final group1 = match.group(1); - - yield group1 ?? match.group(2)!; - } - } - - /// Returns list which content of quotes. - /// Text: `hi this is "example stuff" which 'can be parsed'` will return - /// `List [example stuff, can be parsed]` - Iterable getQuotedText() sync* { - final matches = _quotedTextRegex.allMatches(this.message.content.replaceFirst(commandMatcher, "")); - for(final match in matches) { - yield match.group(1)!; - } - } - - /// Returns list of all code blocks in message - /// Language string `dart, java` will be ignored and not included - /// """ - /// n> eval ```(dart)? - /// await reply(content: 'no to elo'); - /// ``` - /// """ - Iterable getCodeBlocks() sync* { - final matches = _codeBlocksRegex.allMatches(message.content); - for (final match in matches) { - final matchedText = match.group(3); - - if (matchedText != null) { - yield matchedText; - } - } - } -} diff --git a/nyxx_commander/lib/src/CommandHandler.dart b/nyxx_commander/lib/src/CommandHandler.dart deleted file mode 100644 index fdd0b40c6..000000000 --- a/nyxx_commander/lib/src/CommandHandler.dart +++ /dev/null @@ -1,118 +0,0 @@ -part of nyxx_commander; - -/// Base object for [CommandHandler] and [CommandGroup] -abstract class CommandEntity { - /// Executed before executing command. - /// Used to check if command can be executed in current context. - PassHandlerFunction? get beforeHandler => null; - - /// Callback executed after executing command - AfterHandlerFunction? get afterHandler => null; - - /// Name of [CommandEntity] - String get name; - - /// Aliases of [CommandEntity] - List get aliases; - - /// Parent of entity - CommandEntity? get parent; - - /// A list of valid command names - List get commandNames => [if (this.name.isNotEmpty) this.name.toLowerCase(), ...aliases.map((e) => e.toLowerCase())]; - - /// RegEx matching the fully qualified command name with its parents and all aliases - String getFullCommandMatch() { - var parentMatch = ""; - - if (parent != null) { - parentMatch = "${parent!.getFullCommandMatch()} "; - } - - if (this.commandNames.isNotEmpty) { - parentMatch += "(${this.commandNames.join('|')})"; - } - - return parentMatch.toLowerCase(); - } - - /// Returns true if provided String [str] is entity name or alias - bool isEntityName(String str) => commandNames.contains(str.toLowerCase()); -} - -/// Creates command group. Pass a [name] to crated command and commands added -/// via [registerSubCommand] will be subcommands og that group -// ignore: prefer_mixin -class CommandGroup extends CommandEntity with ICommandRegistrable { - @override - final List _commandEntities = []; - - @override - final PassHandlerFunction? beforeHandler; - - @override - final AfterHandlerFunction? afterHandler; - - /// Default [CommandHandler] for [CommandGroup] - it will be executed then no other command from group match - CommandHandler? defaultHandler; - - @override - final String name; - - @override - final List aliases; - - @override - CommandGroup? parent; - - /// Creates command group. Pass a [name] to crated command and commands added - /// via [registerSubCommand] will be subcommands og that group - CommandGroup({this.name = "", this.aliases = const [], this.defaultHandler, this.beforeHandler, this.afterHandler, this.parent}); - - /// Registers default command handler which will be executed if no subcommand is matched to message content - void registerDefaultCommand(CommandHandlerFunction commandHandler, - {PassHandlerFunction? beforeHandler, AfterHandlerFunction? afterHandler}) { - this.defaultHandler = BasicCommandHandler("", commandHandler, beforeHandler: beforeHandler, afterHandler: afterHandler, parent: this); - } - - /// Registers subcommand - void registerSubCommand(String name, CommandHandlerFunction commandHandler, - {PassHandlerFunction? beforeHandler, AfterHandlerFunction? afterHandler}) { - this.registerCommandEntity(BasicCommandHandler(name, commandHandler, beforeHandler: beforeHandler, afterHandler: afterHandler, parent: this)); - } - - /// Registers command as implemented [CommandEntity] class - void registerCommandGroup(CommandGroup commandGroup) => this.registerCommandEntity(commandGroup..parent = this); -} - -/// Handles command execution - requires to implement [name] field which -/// returns name of command to match message content, and [commandHandler] callback -/// which is fired when command matches message content. -abstract class CommandHandler extends CommandEntity { - /// Main command callback - CommandHandlerFunction get commandHandler; -} - -/// Basic implementation of command handler. Used internally in library. -class BasicCommandHandler extends CommandHandler { - @override - final PassHandlerFunction? beforeHandler; - - @override - final AfterHandlerFunction? afterHandler; - - @override - CommandHandlerFunction commandHandler; - - @override - final String name; - - @override - final List aliases; - - @override - CommandGroup? parent; - - /// Basic implementation of command handler. Used internally in library. - BasicCommandHandler(this.name, this.commandHandler, {this.aliases = const [], this.beforeHandler, this.afterHandler, this.parent}); -} diff --git a/nyxx_commander/lib/src/Commander.dart b/nyxx_commander/lib/src/Commander.dart deleted file mode 100644 index 547adc0fd..000000000 --- a/nyxx_commander/lib/src/Commander.dart +++ /dev/null @@ -1,230 +0,0 @@ -part of nyxx_commander; - -/// Used to determine if command can be executed in given environment. -/// Return true to allow executing command or false otherwise. -typedef PassHandlerFunction = FutureOr Function(CommandContext context); - -/// Handler for executing command logic. -typedef CommandHandlerFunction = FutureOr Function(CommandContext context, String message); - -/// Handler for executing logic after executing command. -typedef AfterHandlerFunction = FutureOr Function(CommandContext context); - -/// Handler used to determine prefix for command in given environment. -/// Can be used to define different prefixes for different guild, users or dms. -/// Return String containing prefix or null if command cannot be executed. -typedef PrefixHandlerFunction = FutureOr Function(Message message); - -/// Callback to customize logger output when command is executed. -typedef LoggerHandlerFunction = FutureOr Function(CommandContext context, String commandName, Logger logger); - -/// Callback called when command executions returns with [Exception] or [Error] ([exception] variable could be either). -typedef CommandExecutionError = FutureOr Function(CommandContext context, dynamic exception); - -/// Lightweight command framework. Doesn't use `dart:mirrors` and can be used in browser. -/// While constructing specify prefix which is string with prefix or -/// implement [PrefixHandlerFunction] for more fine control over where and in what conditions commands are executed. -/// -/// Allows to specify callbacks which are executed before and after command - also on per command basis. -/// beforeCommandHandler callbacks are executed only command exists and is matched with message content. -// ignore: prefer_mixin -class Commander with ICommandRegistrable { - late final PrefixHandlerFunction _prefixHandler; - late final PassHandlerFunction? _beforeCommandHandler; - late final AfterHandlerFunction? _afterHandlerFunction; - late final LoggerHandlerFunction _loggerHandlerFunction; - late final CommandExecutionError? _commandExecutionError; - - @override - final List _commandEntities = []; - - final Logger _logger = Logger("Commander"); - - /// Resolves prefix for given [message]. Returns null if there is no prefix for given [message] which - /// means command wouldn't execute in given context. - FutureOr getPrefixForMessage(Message message) => _prefixHandler(message); - - /// Returns unmodifiable list of registered commands. - List get commands => List.unmodifiable(this._commandEntities); - - /// Either [prefix] or [prefixHandler] must be specified otherwise program will exit. - /// Allows to specify additional [beforeCommandHandler] executed before main command callback, - /// and [afterCommandHandler] executed after main command callback. - Commander(Nyxx client, - {String? prefix, - PrefixHandlerFunction? prefixHandler, - PassHandlerFunction? beforeCommandHandler, - AfterHandlerFunction? afterCommandHandler, - LoggerHandlerFunction? loggerHandlerFunction, - CommandExecutionError? commandExecutionError}) { - if (!_hasRequiredIntents(client)) { - _logger.shout("Commander cannot start without required intents (directMessages, guildMessages, guilds)"); - exit(1); - } - - if (prefix == null && prefixHandler == null) { - _logger.shout("Commander cannot start without both prefix and prefixHandler"); - exit(1); - } - - if (prefix == null) { - _prefixHandler = prefixHandler!; - } else { - _prefixHandler = (_) => prefix; - } - - this._beforeCommandHandler = beforeCommandHandler; - this._afterHandlerFunction = afterCommandHandler; - this._commandExecutionError = commandExecutionError; - this._loggerHandlerFunction = loggerHandlerFunction ?? _defaultLogger; - - client.onMessageReceived.listen(_handleMessage); - - this._logger.info("Commander ready!"); - } - - /// Registers command with given [commandName]. Allows to specify command specific before and after command execution callbacks - void registerCommand(String commandName, CommandHandlerFunction commandHandler, {PassHandlerFunction? beforeHandler, AfterHandlerFunction? afterHandler}) { - this.registerCommandEntity(BasicCommandHandler(commandName, commandHandler, beforeHandler: beforeHandler, afterHandler: afterHandler)); - } - - /// Registers command as implemented [CommandEntity] class - void registerCommandGroup(CommandGroup commandGroup) => this.registerCommandEntity(commandGroup); - - Future _handleMessage(MessageReceivedEvent event) async { - final prefix = await _prefixHandler(event.message); - if (prefix == null) { - return; - } - - if(!event.message.content.startsWith(prefix)) { - return; - } - - this._logger.finer("Attempting to execute command from message: [${event.message.content}] from [${event.message.author.tag}]"); - - // Find matching command with given message content - final matchingCommand = _CommandMatcher._findMatchingCommand(event.message.content.toLowerCase().replaceFirst(prefix, "").trim().split(" "), _commandEntities) as CommandHandler?; - - if(matchingCommand == null) { - return; - } - - // Builds a RegEx that matches the full command including their parents and all possible - // aliases of the final command entity and their parents. - // Example: (?(quote|q) (remove|rm)) - // This will match the command `quote remove`, `q remove`, `quote rm` and `q rm` - - final match = RegExp("(?${matchingCommand.getFullCommandMatch().trim()})").firstMatch(event.message.content.toLowerCase()); - final finalCommand = match?.namedGroup("finalCommand"); - - this._logger.finer("Preparing command for execution: Command name: $finalCommand"); - - // construct CommandContext - final context = CommandContext._new( - await event.message.channel.getOrDownload(), - event.message.author, - event.message is GuildMessage ? (event.message as GuildMessage).guild.getFromCache()! : null, - event.message, - "$prefix$finalCommand", - ); - - // Invoke before handler for commands - if (!(await _invokeBeforeHandler(matchingCommand, context))) { - return; - } - - // Invoke before handler for commander - if(this._beforeCommandHandler != null && !(await this._beforeCommandHandler!(context))) { - return; - } - - // Execute command - try { - await matchingCommand.commandHandler(context, event.message.content); - } on Exception catch (e) { - if(this._commandExecutionError != null) { - await _commandExecutionError!(context, e); - } - - this._logger.fine("Command [$finalCommand] executed with Exception: $e"); - } on Error catch (e) { - if(this._commandExecutionError != null) { - await _commandExecutionError!(context, e); - } - - this._logger.fine("Command [$finalCommand] executed with Error: $e"); - } - - // execute logger callback - _loggerHandlerFunction(context, finalCommand!, this._logger); - - // invoke after handler of command - await _invokeAfterHandler(matchingCommand, context); - - // Invoke after handler for commander - if (this._afterHandlerFunction != null) { - this._afterHandlerFunction!(context); - } - } - - // Invokes command after handler and its parents - Future _invokeAfterHandler(CommandEntity? commandEntity, CommandContext context) async { - if(commandEntity == null) { - return; - } - - if(commandEntity.afterHandler != null) { - await commandEntity.afterHandler!(context); - } - - if(commandEntity.parent != null) { - await _invokeAfterHandler(commandEntity.parent, context); - } - } - - // Invokes command before handler and its parents. It will check for next before handlers if top handler returns true. - Future _invokeBeforeHandler(CommandEntity? commandEntity, CommandContext context) async { - if(commandEntity == null) { - return true; - } - - if(commandEntity.beforeHandler == null) { - return _invokeBeforeHandler(commandEntity.parent, context); - } - - if(await commandEntity.beforeHandler!(context)) { - return _invokeBeforeHandler(commandEntity.parent, context); - } - - return false; - } - - FutureOr _defaultLogger(CommandContext ctx, String commandName, Logger logger) { - logger.info("Command [$commandName] executed by [${ctx.author.tag}]"); - } - - bool _hasRequiredIntents(Nyxx client) => - PermissionsUtils.isApplied(client.intents, GatewayIntents.guildMessages) - || PermissionsUtils.isApplied(client.intents, GatewayIntents.directMessages) - || PermissionsUtils.isApplied(client.intents, GatewayIntents.guilds) - || PermissionsUtils.isApplied(client.intents, GatewayIntents.guilds); -} - -/// Provides common functionality for entities which can register subcommand or sub command groups. -abstract class ICommandRegistrable { - List get _commandEntities; - - /// Registers [CommandEntity] within context of this instance. Throws error if there is command with same name as provided. - void registerCommandEntity(CommandEntity entity) { - if (this._commandEntities.any((element) => element.isEntityName(entity.name) )) { - throw Exception("Command name should be unique! There is already command with name: ${entity.name}}"); - } - - if (entity is CommandGroup && entity.name.isEmpty && entity.aliases.isNotEmpty) { - throw Exception("Command group cannot have aliases if its name is empty! Provided aliases: [${entity.aliases.join(", ")}]"); - } - - this._commandEntities.add(entity); - } -} diff --git a/nyxx_commander/lib/src/utils.dart b/nyxx_commander/lib/src/utils.dart deleted file mode 100644 index e8c135531..000000000 --- a/nyxx_commander/lib/src/utils.dart +++ /dev/null @@ -1,38 +0,0 @@ -part of nyxx_commander; - -class _CommandMatcher { - /// Matches [commands] from [messageParts]. Performs recursive lookup on available commands and it's children. - static CommandEntity? _findMatchingCommand(Iterable messageParts, Iterable commands) { - for (final entity in commands) { - if(entity is CommandGroup && entity.name == "") { - final e = _findMatchingCommand(messageParts, entity._commandEntities); - - if (e != null) { - return e; - } - } - - if (entity is CommandGroup && entity.isEntityName(messageParts.first)) { - if (messageParts.length == 1 && entity.defaultHandler != null) { - return entity.defaultHandler; - } else if (messageParts.length == 1 && entity.defaultHandler == null) { - return null; - } - - final e = _findMatchingCommand(messageParts.skip(1), entity._commandEntities); - - if (e != null) { - return e; - } else if (entity.defaultHandler != null) { - return entity.defaultHandler; - } - } - - if (entity is CommandHandler && entity.isEntityName(messageParts.first)) { - return entity; - } - } - - return null; - } -} diff --git a/nyxx_commander/pubspec.yaml b/nyxx_commander/pubspec.yaml deleted file mode 100644 index 3378bb745..000000000 --- a/nyxx_commander/pubspec.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: nyxx_commander -version: 2.0.1 -description: Nyxx Commander Module. Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. -homepage: https://github.com/nyxx-discord/nyxx -repository: https://github.com/nyxx-discord/nyxx -documentation: https://nyxx.l7ssha.xyz -issue_tracker: https://github.com/nyxx-discord/nyxx/issues - -environment: - sdk: '>=2.13.0 <3.0.0' - -dependencies: - http: "^0.13.3" - logging: "^1.0.1" - nyxx: "^2.0.0" diff --git a/nyxx_commander/test/commander-test.dart b/nyxx_commander/test/commander-test.dart deleted file mode 100644 index f6e04d75d..000000000 --- a/nyxx_commander/test/commander-test.dart +++ /dev/null @@ -1,86 +0,0 @@ -import "dart:async"; -import "dart:io"; - -import "package:nyxx/nyxx.dart"; -import "package:nyxx_commander/commander.dart"; - -void main() { - final bot = Nyxx(Platform.environment["TEST_TOKEN"]!, GatewayIntents.allUnprivileged, ignoreExceptions: false); - - bot.onMessageReceived.listen((event) async { - if (event.message.content == "Test 1") { - event.message.delete(); // ignore: unawaited_futures - } - - if (event.message.content == "Test 2") { - event.message.delete(); // ignore: unawaited_futures - } - - if (event.message.content == "Test 10") { - event.message.delete(); // ignore: unawaited_futures - } - - if (event.message.content == "Test 11") { - await event.message.delete(); - } - - if (event.message.content == "Test 12") { - await event.message.delete(); - - await event.message.channel.getFromCache()?.sendMessage(MessageBuilder.content("Commander tests completed successfully!")); - exit(0); - } - }); - - bot.onReady.listen((e) async { - final channel = await bot.fetchChannel(Snowflake("846139169818017812")); - - await channel.sendMessage(MessageBuilder.content("Testing Commander")); - - final msg1 = await channel.sendMessage(MessageBuilder.content("test>test1")); - msg1.delete(); // ignore: unawaited_futures - - final msg2 = await channel.sendMessage(MessageBuilder.content("test>test2 arg1")); - msg2.delete(); // ignore: unawaited_futures - - final msg3 = await channel.sendMessage(MessageBuilder.content("test>test3")); - msg3.delete(); // ignore: unawaited_futures - - final msg4 = await channel.sendMessage(MessageBuilder.content("test>test4")); - msg4.delete(); // ignore: unawaited_futures - - final msg5 = await channel.sendMessage(MessageBuilder.content("test>test4 test5")); - msg5.delete(); // ignore: unawaited_futures - }); - - Commander(bot, prefix: "test>", beforeCommandHandler: (context) async { - if (context.message.content.endsWith("test3")) { - await context.channel.sendMessage(MessageBuilder.content("Test 10")); - return true; - } - - return true; - }) - ..registerCommand("test1", (context, message) async { - await context.channel.sendMessage(MessageBuilder.content("Test 1")); - }) - ..registerCommand("test2", (context, message) async { - final args = message.split(" "); - - if (args.length == 2 && args.last == "arg1") { - await context.channel.sendMessage(MessageBuilder.content("Test 2")); - } - }) - ..registerCommand("test3", (context, message) async { - await context.message.delete(); - }) - ..registerCommandGroup(CommandGroup(name: "test4") - ..registerDefaultCommand((context, message) => context.channel.sendMessage(MessageBuilder.content("Test 11"))) - ..registerSubCommand("test5", (context, message) => context.channel.sendMessage(MessageBuilder.content("Test 12"))) - ); - - Timer(const Duration(seconds: 60), () { - print("Timed out waiting for messages"); - exit(1); - }); -} diff --git a/nyxx_extensions/CHANGELOG.md b/nyxx_extensions/CHANGELOG.md deleted file mode 100644 index 5cdb51c58..000000000 --- a/nyxx_extensions/CHANGELOG.md +++ /dev/null @@ -1,34 +0,0 @@ -## 2.0.1 -_15.10.2021_ - -- Move to Apache 2 license - -## 2.0.0 -_03.10.2021_ - -> Bumped version to 2.0 for compatibility with nyxx - -- Added compatibility for nyxx 2.0.0-rc2 -- Implemented mutual guilds extension method (9a8bb35) - -## 2.0.0-rc.3 -_25.04.2021_ - -> **Release Candidate 2 for stable version. Requires dart sdk 2.12** - - - Added compatifility for nyxx 2.0.0-rc2 - - Implemented mutual guilds extension method (9a8bb35) - -## 1.0.0 -_24.08.2020_ - -> **Stable release - breaks with previous versions - this version required Dart 2.9 stable and non-nullable experiment to be enabled to function** - -> **`1.0.0` drops support for browser. Nyxx will now run only on VM** - - - New emoji module for fetching available emoji info - - Pagination module for created paginated messages - - Scheduler module for invoking repeatable actions - - Additional general utils - - Message resolver module for resolving raw message content into human readable form - - Attachment extensions for vm diff --git a/nyxx_extensions/LICENSE b/nyxx_extensions/LICENSE deleted file mode 100644 index 1dfc579d0..000000000 --- a/nyxx_extensions/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 Szymon Uglis, Harry Bairstow and contributors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/nyxx_extensions/README.md b/nyxx_extensions/README.md deleted file mode 100644 index ec9cc255a..000000000 --- a/nyxx_extensions/README.md +++ /dev/null @@ -1,105 +0,0 @@ -# nyxx_extensions - -[![pub](https://img.shields.io/pub/v/nyxx.svg)](https://pub.dartlang.org/packages/nyxx) -[![documentation](https://img.shields.io/badge/Documentation-nyxx-yellow.svg)](https://www.dartdocs.org/documentation/nyxx/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.commander-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.commander/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.interactions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.interactions/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.extentions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.extensions/latest/) - -Simple, robust framework for creating discord bots for Dart language. - -
- -### Features - -- **Slash commands support**
- Supports and provides easy API for creating and handling slash commands -- **Commands framework included**
- A fast way to create a bot with command support. Implementing the framework is simple - and everything is done automatically. -- **Cross Platform**
- Nyxx works on the command line, in the browser, and on mobile devices. -- **Fine Control**
- Nyxx allows you to control every outgoing HTTP request or WebSocket message. -- **Complete**
- Nyxx supports nearly all Discord API endpoints. - - -## Quick example - -Basic usage: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - bot.onMessageReceived.listen((event) { - if (event.message.content == "!ping") { - event.message.channel.getFromCache()?.sendMessage(content: "Pong!"); - } - }); -} -``` - -Slash commands: -```dart -void main() { - final bot = Nyxx("<%TOKEN%>", GatewayIntents.allUnprivileged); - Interactions(bot) - ..registerSlashCommand( - SlashCommandBuilder("hi", "This is example slash command", []) - ..registerHandler((event) async { - await event.acknowledge(); - - await event.respond(MessageBuilder.content("Hello World!")); - }) - ); -} -``` - -Commands: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - Commander(bot, prefix: "!!!") - ..registerCommand("ping", (context, message) => context.reply(content: "Pong!")); -} -``` - -## More examples - -Nyxx examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx/example). - -Commander examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx.commander/example) - -Slash commands (interactions) examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx.interactions/example) - -### Example bots -- [Running on Dart](https://github.com/l7ssha/running_on_dart) - -## Documentation, help and examples - -**Dartdoc documentation is hosted on [pub](https://www.dartdocs.org/documentation/nyxx/latest/). -This wiki just fills gap in docs with more descriptive guides and tutorials.** - -#### [Discord API docs](https://discordapp.com/developers/docs/intro) -Discord API documentation features rich descriptions about all topics that nyxx covers. - -#### [Discord API Guild](https://discord.gg/discord-api) -The unofficial guild for Discord Bot developers. To get help with nyxx check `#dart_nyxx` channel. - -#### [Dartdocs](https://www.dartdocs.org/documentation/nyxx/latest/) -The dartdocs page will always have the documentation for the latest release. - -#### [Dev docs](https://nyxx.l7ssha.xyz) -You can read about upcoming changes in the library on my website. - -#### [Wiki](https://github.com/l7ssha/nyxx/wiki) -Wiki documentation are designed to match the latest Nyxx release. - -## Contributing to Nyxx - -Read [contributing document](https://github.com/l7ssha/nyxx/blob/development/CONTRIBUTING.md) - -## Credits - -* [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx). diff --git a/nyxx_extensions/analysis_options.yaml b/nyxx_extensions/analysis_options.yaml deleted file mode 100644 index 128725250..000000000 --- a/nyxx_extensions/analysis_options.yaml +++ /dev/null @@ -1,106 +0,0 @@ -analyzer: - strong-mode: - implicit-casts: false -linter: - rules: - - avoid_empty_else - - comment_references - - control_flow_in_finally - - empty_statements - - hash_and_equals - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - avoid_slow_async_io - - cancel_subscriptions - - test_types_in_equals - - throw_in_finally - - valid_regexps - - always_declare_return_types - - annotate_overrides - - avoid_init_to_null - - avoid_return_types_on_setters - - await_only_futures - - camel_case_types - - constant_identifier_names - - empty_constructor_bodies - - library_names - - library_prefixes - - non_constant_identifier_names - - only_throw_errors - - package_api_docs - - package_prefixed_library_names - - prefer_is_not_empty - - slash_for_doc_comments - - type_init_formals - - unnecessary_getters_setters - - package_names - - unnecessary_await_in_return - - use_function_type_syntax_for_parameters - - avoid_returning_null_for_future - - no_duplicate_case_values - - unnecessary_statements - - always_require_non_null_named_parameters - - always_put_required_named_parameters_first - - avoid_catches_without_on_clauses - - avoid_function_literals_in_foreach_calls - - avoid_redundant_argument_values - - avoid_returning_null - - avoid_returning_null_for_void - - avoid_returning_this - - camel_case_extensions - - curly_braces_in_flow_control_structures - - directives_ordering - - empty_catches - - join_return_with_assignment - - leading_newlines_in_multiline_strings - - missing_whitespace_between_adjacent_strings - - no_runtimeType_toString - - null_closures - - omit_local_variable_types - - one_member_abstracts - - prefer_adjacent_string_concatenation - - prefer_collection_literals - - prefer_conditional_assignment - - prefer_const_constructors - - prefer_const_constructors_in_immutables - - prefer_const_declarations - - prefer_const_literals_to_create_immutables - - prefer_constructors_over_static_methods - - prefer_contains - - prefer_double_quotes - - prefer_equal_for_default_values - - prefer_expression_function_bodies - - prefer_final_fields - - prefer_final_in_for_each - - prefer_final_locals - - prefer_for_elements_to_map_fromIterable - - prefer_foreach - - prefer_function_declarations_over_variables - - prefer_generic_function_type_aliases - - prefer_if_elements_to_conditional_expressions - - prefer_if_null_operators - - prefer_initializing_formals - - prefer_inlined_adds - - prefer_int_literals - - prefer_interpolation_to_compose_strings - - prefer_is_empty - - provide_deprecation_message - - prefer_typing_uninitialized_variables - - public_member_api_docs - - unawaited_futures - - unnecessary_brace_in_string_interps - - unnecessary_lambdas - - unnecessary_null_in_if_null_operators - - unnecessary_parenthesis - - unnecessary_raw_strings - - unnecessary_string_escapes - - use_rethrow_when_possible - - use_string_buffers - - void_checks - - use_to_and_as_if_applicable - - sort_pub_dependencies - - prefer_is_not_operator - - prefer_iterable_whereType - - prefer_mixin - - prefer_null_aware_operators - - prefer_spread_collections diff --git a/nyxx_extensions/example/example.dart b/nyxx_extensions/example/example.dart deleted file mode 100644 index 169e09485..000000000 --- a/nyxx_extensions/example/example.dart +++ /dev/null @@ -1,28 +0,0 @@ -import "package:nyxx/nyxx.dart"; -import "package:nyxx_extensions/emoji.dart" as emoji_extension; -import "package:nyxx_extensions/src/message_resolver/message_resolver.dart" as message_resolver_extension; - -// nyxx.extensions contains several different extensions -// that could simplify making and implementing bots. -void main() async { - // Emoji extension would allow to download and fetch discord emoji definitions - // from resource shared by Emzi. - // Emoji utils can cache results to do not download json document each time - final allEmojis = emoji_extension.getAllEmojiDefinitions(); - - // Its also possible to filter the emojis based on predicate - final filteredEmojis = emoji_extension.filterEmojiDefinitions( - (emojiDefinition) => emojiDefinition.primaryName.startsWith("smile") - ); - - // Needed for next extension - final bot = Nyxx("token", GatewayIntents.allUnprivileged); - - // Message Resolver extension allows to transform raw string message content - // to format that user is seeing - final messageResolver = message_resolver_extension.MessageResolver(bot); - - // resolve method will return message according to set handling settings in - // MessageResolver constructor. - final resolvedMessage = messageResolver.resolve("This is raw content. "); -} diff --git a/nyxx_extensions/lib/attachment_extension.dart b/nyxx_extensions/lib/attachment_extension.dart deleted file mode 100644 index a24ba6419..000000000 --- a/nyxx_extensions/lib/attachment_extension.dart +++ /dev/null @@ -1 +0,0 @@ -export "src/attachment_extension.dart"; diff --git a/nyxx_extensions/lib/embedbuilder_extension.dart b/nyxx_extensions/lib/embedbuilder_extension.dart deleted file mode 100644 index 1403ecd81..000000000 --- a/nyxx_extensions/lib/embedbuilder_extension.dart +++ /dev/null @@ -1 +0,0 @@ -export "src/embedbuilder_extension.dart"; diff --git a/nyxx_extensions/lib/emoji.dart b/nyxx_extensions/lib/emoji.dart deleted file mode 100644 index 3786f22be..000000000 --- a/nyxx_extensions/lib/emoji.dart +++ /dev/null @@ -1,11 +0,0 @@ -library emoji; - -import "dart:convert"; - -import "package:nyxx/nyxx.dart"; -import "package:http/http.dart" as http; - -part "src/emoji/EmojiDefinition.dart"; -part "src/emoji/EmojiUtils.dart"; - -typedef RawApiMap = Map; diff --git a/nyxx_extensions/lib/member_extension.dart b/nyxx_extensions/lib/member_extension.dart deleted file mode 100644 index 444b0fa1c..000000000 --- a/nyxx_extensions/lib/member_extension.dart +++ /dev/null @@ -1 +0,0 @@ -export "package:nyxx_extensions/member_extension.dart"; diff --git a/nyxx_extensions/lib/message_resolver.dart b/nyxx_extensions/lib/message_resolver.dart deleted file mode 100644 index 662ceb924..000000000 --- a/nyxx_extensions/lib/message_resolver.dart +++ /dev/null @@ -1,2 +0,0 @@ -export "src/message_resolver/Regexes.dart"; -export "src/message_resolver/message_resolver.dart"; diff --git a/nyxx_extensions/lib/src/attachment_extension.dart b/nyxx_extensions/lib/src/attachment_extension.dart deleted file mode 100644 index dd5044c2a..000000000 --- a/nyxx_extensions/lib/src/attachment_extension.dart +++ /dev/null @@ -1,18 +0,0 @@ -import "dart:io" show File, FileMode; -import "dart:typed_data"; - -import "package:http/http.dart" as http; -import "package:nyxx/nyxx.dart" show Attachment; - -/// Extensions for downloading attachment -extension DownloadAttachmentExtensions on Attachment { - /// Downloads [Attachment] and saves to given [file]. - /// Returns modified file - Future downloadAsFile(File file) async { - final dataBytes = await this.downloadAsBytes(); - return file.writeAsBytes(dataBytes, mode: FileMode.writeOnly); - } - - /// Downloads attachment as returns bytes of downloaded file. - Future downloadAsBytes() async => (await http.get(Uri.parse(this.url))).bodyBytes; -} diff --git a/nyxx_extensions/lib/src/embedbuilder_extension.dart b/nyxx_extensions/lib/src/embedbuilder_extension.dart deleted file mode 100644 index 560ed5221..000000000 --- a/nyxx_extensions/lib/src/embedbuilder_extension.dart +++ /dev/null @@ -1,61 +0,0 @@ -import "package:nyxx/nyxx.dart"; - -typedef RawApiMap = Map; - -/// Collection of extensions for [EmbedFieldBuilder] -extension EmbedFieldBuilderJson on EmbedFieldBuilder { - /// Returns a [EmbedFieldBuilder] with data from the raw json - EmbedFieldBuilder importJson(RawApiMap raw) { - this.name = raw["name"]; - this.content = raw["value"]; - this.inline = raw["inline"] as bool?; - return this; - } -} - -/// Collection of extensions for [EmbedFooterBuilder] -extension EmbedFooterBuilderJson on EmbedFooterBuilder { - /// Returns a [EmbedFooterBuilder] with data from the raw json - EmbedFooterBuilder importJson(Map raw) { - this.text = raw["text"]; - this.iconUrl = raw["icon_url"]; - return this; - } -} - -/// Collection of extensions for [EmbedAuthorBuilder] -extension EmbedAuthorBuilderJson on EmbedAuthorBuilder { - /// Returns a [EmbedAuthorBuilder] with data from the raw json - EmbedAuthorBuilder importJson(Map raw) { - this.name = raw["name"]; - this.url = raw["url"]; - this.iconUrl = raw["icon_url"]; - return this; - } -} - -/// Collection of extensions for [EmbedBuilder] -extension EmbedBuilderJson on EmbedBuilder { - /// Returns a [EmbedBuilder] with data from the raw json - EmbedBuilder importJson(RawApiMap raw) { - this.title = raw["title"] as String?; - this.description = raw["description"] as String?; - this.url = raw["url"] as String?; - this.color = raw["color"] != null ? DiscordColor.fromInt(raw["color"] as int) : null; - this.timestamp = raw["timestamp"] != null ? DateTime.parse(raw["timestamp"] as String) : null; - this.footer = raw["footer"] != null - ? EmbedFooterBuilder().importJson(raw["footer"] as Map) - : null; - this.imageUrl = raw["image"]["url"] as String?; - this.thumbnailUrl = raw["thumbnail"]["url"] as String?; - this.author = raw["author"] != null - ? EmbedAuthorBuilder().importJson(raw["author"] as Map) - : null; - - for(final rawFields in raw["fields"] as List) { - this.fields.add(EmbedFieldBuilder().importJson(rawFields as RawApiMap)); - } - - return this; - } -} diff --git a/nyxx_extensions/lib/src/emoji/EmojiDefinition.dart b/nyxx_extensions/lib/src/emoji/EmojiDefinition.dart deleted file mode 100644 index 6169fd5a2..000000000 --- a/nyxx_extensions/lib/src/emoji/EmojiDefinition.dart +++ /dev/null @@ -1,34 +0,0 @@ -part of emoji; - -/// Wrapper class around discords emojis data -class EmojiDefinition { - /// Name of emoji - late final String primaryName; - - /// List of alternative names of emoji - late final Iterable names; - - /// Literal emoji - late final String rawEmoji; - - /// List of utf32 code points - late final Iterable codePoints; - - /// Name of asset used in discords frontend for this emoji - late final String assetFileName; - - /// Url of emoji picture - late final String assetUrl; - - EmojiDefinition._new(RawApiMap raw) { - this.primaryName = raw["primaryName"] as String; - this.names = (raw["names"] as Iterable).cast(); - this.rawEmoji = raw["surrogates"] as String; - this.codePoints = (raw["utf32codepoints"] as Iterable).cast(); - this.assetFileName = raw["assetFileName"] as String; - this.assetUrl = raw["assetUrl"] as String; - } - - /// Returns [UnicodeEmoji] object of this - UnicodeEmoji toEmoji() => UnicodeEmoji(rawEmoji); -} diff --git a/nyxx_extensions/lib/src/emoji/EmojiUtils.dart b/nyxx_extensions/lib/src/emoji/EmojiUtils.dart deleted file mode 100644 index 2941579eb..000000000 --- a/nyxx_extensions/lib/src/emoji/EmojiUtils.dart +++ /dev/null @@ -1,37 +0,0 @@ -part of emoji; - -List _emojisCache = []; - -Future _downloadEmojiData() async { - final request = http.Request("GET", emojiDataUri); - final requestBody = await (await request.send()).stream.bytesToString(); - - return jsonDecode(requestBody) as RawApiMap; -} - -/// Emoji definitions uri -final Uri emojiDataUri = Uri.parse("https://static.emzi0767.com/misc/discordEmojiMap.json"); - -/// Returns emoji based on given [predicate]. Allows to cache results via [cache] parameter. -Future filterEmojiDefinitions(bool Function(EmojiDefinition) predicate, {bool cache = false}) async => - getAllEmojiDefinitions(cache: cache).firstWhere(predicate); - -/// Returns all possible [EmojiDefinition]s. Allows to cache results via [cache] parameter. -/// If emojis are cached it will resolve immediately with result. -Stream getAllEmojiDefinitions({bool cache = false}) async* { - if (_emojisCache.isNotEmpty) { - yield* Stream.fromIterable(_emojisCache); - } - - final rawData = await _downloadEmojiData(); - - for (final emojiDefinition in rawData["emojiDefinitions"]) { - final definition = EmojiDefinition._new(emojiDefinition as RawApiMap); - - if(cache) { - _emojisCache.add(definition); - } - - yield definition; - } -} diff --git a/nyxx_extensions/lib/src/member_extension.dart b/nyxx_extensions/lib/src/member_extension.dart deleted file mode 100644 index fe2ae7fe1..000000000 --- a/nyxx_extensions/lib/src/member_extension.dart +++ /dev/null @@ -1,22 +0,0 @@ -import "package:nyxx/nyxx.dart"; - -/// Collection of extensions for [Member] -extension MemberExtension on User { - /// Fetches all mutual guilds for [User] that bot has access to. - /// Note it will try to download users via REST api so bot could get rate limited. - Future> fetchMutualGuilds() async { - final result = {}; - - for (final guild in this.client.guilds.values) { - try { - final member = guild.members[this.id] - ?? await guild.fetchMember(this.id); - - result[guild] = member; - // ignore: empty_catches - } on Exception { } - } - - return result; - } -} diff --git a/nyxx_extensions/lib/src/message_resolver/Regexes.dart b/nyxx_extensions/lib/src/message_resolver/Regexes.dart deleted file mode 100644 index 5f4133178..000000000 --- a/nyxx_extensions/lib/src/message_resolver/Regexes.dart +++ /dev/null @@ -1,18 +0,0 @@ - -/// Collection of regexes for message entities -class Regexes { - /// Matches user mention - static final userMentionRegex = RegExp(r"<@!?(\d+)>"); - - /// Matches role mention - static final roleMentionRegex = RegExp(r"<@&(\d+)>"); - - /// Matches everyone/here mention - static final everyoneMentionRegex = RegExp("(@(?:(everyone|here)))"); - - /// Matches channel mention - static final channelMentionRegex = RegExp(r"<#(\d+)>"); - - /// Matches guild emoji - static final emojiMentionRegex = RegExp(r"<(a?):(\w+):(\d+)>"); -} diff --git a/nyxx_extensions/lib/src/message_resolver/message_resolver.dart b/nyxx_extensions/lib/src/message_resolver/message_resolver.dart deleted file mode 100644 index 8d58939b2..000000000 --- a/nyxx_extensions/lib/src/message_resolver/message_resolver.dart +++ /dev/null @@ -1,295 +0,0 @@ -import "dart:async"; - -import "package:nyxx/nyxx.dart" show TextGuildChannel, Message, Nyxx, Snowflake; - -import "Regexes.dart" show Regexes; - -/// Possible types of tag handling for [MessageResolver] -enum TagHandling { - /// Ignores tag handling completely - leaves content as is. - ignore, - /// Removes tag completely. - remove, - /// Returns name of tag, eg. `<@932489234> -> @l7ssha` - name, - /// Returns name of tag without mention prefix, eg. `<@932489234> -> l7ssha` - nameNoPrefix, - /// Returns name of the tag with full possible data, eg. `<@932489234> -> @l7ssha#6712` - fullName, - /// Returns name of the tag with full possible data without mention prefix, eg. `<@932489234> -> l7ssha#6712` - fullNameNoPrefix, - /// Sanitizes tag to form that client wont treat it as valid tag - sanitize -} - -/// Extends [Message] class with [MessageResolver] -extension MessageResolverExtension on Message { - /// Resolves raw message content to human readable string. - /// Allows to set what to do with particular parts of message. - /// Each mention, channel reference and emoji can be resolved by [TagHandling] - FutureOr resolveContent( { - TagHandling userTagHandling = TagHandling.sanitize, - TagHandling roleTagHandling = TagHandling.sanitize, - TagHandling everyoneTagHandling = TagHandling.sanitize, - TagHandling channelTagHandling = TagHandling.sanitize, - TagHandling emojiTagHandling = TagHandling.sanitize - }) { - if(this.content.isEmpty) { - return ""; - } - - return MessageResolver(this.client as Nyxx, - userTagHandling: userTagHandling, - roleTagHandling: roleTagHandling, - everyoneTagHandling: everyoneTagHandling, - channelTagHandling: channelTagHandling, - emojiTagHandling: everyoneTagHandling).resolve(this.content); - } -} - -/// Allows to return custom messages in case of missing entities when resolving message content. -/// [entityType] could be either `role`, `channel` or `user`. -typedef MissingEntityHandler = FutureOr Function(String entityType); - -/// Resolves raw message content to human readable string. -/// Allows to set what to do with particular parts of message. -/// Each mention, channel reference and emoji can be resolved by [TagHandling] -class MessageResolver { - final Nyxx _client; - static const String _whiteSpaceCharacter = "‎"; - - /// Handles resolving of user mentions - final TagHandling userTagHandling; - - /// Handles resolving of role mentions - final TagHandling roleTagHandling; - - /// Handles resolving of everyone/here mentions - final TagHandling everyoneTagHandling; - - /// Handles resolving of channels mentions - final TagHandling channelTagHandling; - - /// Handles resolving of guild emojis - final TagHandling emojiTagHandling; - - /// Handles what will be returned in case if entity cannot be resolved - late final MissingEntityHandler missingEntityHandler; - - /// Create message resolver with given options - MessageResolver(this._client, { - this.userTagHandling = TagHandling.sanitize, - this.roleTagHandling = TagHandling.sanitize, - this.everyoneTagHandling = TagHandling.sanitize, - this.channelTagHandling = TagHandling.sanitize, - this.emojiTagHandling = TagHandling.sanitize, - MissingEntityHandler? missingEntityHandler - }) { - if (missingEntityHandler == null) { - this.missingEntityHandler = _defaultMissingEntityHandler; - } else { - this.missingEntityHandler = missingEntityHandler; - } - } - - /// Create message resolver with tag handlers set to [tagHandling]. - factory MessageResolver.uniform(Nyxx client, TagHandling tagHandling) => - MessageResolver(client, - userTagHandling: tagHandling, - roleTagHandling: tagHandling, - everyoneTagHandling: tagHandling, - channelTagHandling: tagHandling, - emojiTagHandling: tagHandling - ); - - /// Resolves raw [messageContent] into human readable form. - Future resolve(String messageContent) async { - if (messageContent.trim().isEmpty) { - return ""; - } - - final messageParts = messageContent.split(" "); - final outputBuffer = StringBuffer(); - - for(final part in messageParts) { - outputBuffer.write(" "); - - final userMatch = Regexes.userMentionRegex.firstMatch(part); - if (userMatch != null) { - outputBuffer.write(await this._resoleUserMention(userMatch, part)); - continue; - } - - final roleMatch = Regexes.roleMentionRegex.firstMatch(part); - if (roleMatch != null) { - outputBuffer.write(await this._resolveRoleMention(roleMatch, part)); - continue; - } - - final everyoneMatch = Regexes.everyoneMentionRegex.firstMatch(part); - if (everyoneMatch != null) { - outputBuffer.write(await this._resolveEveryone(everyoneMatch, part)); - continue; - } - - final channelMatch = Regexes.channelMentionRegex.firstMatch(part); - if (channelMatch != null) { - outputBuffer.write(await this._resolveChannel(channelMatch, part)); - continue; - } - - final emojiMatch = Regexes.emojiMentionRegex.firstMatch(part); - if (emojiMatch != null) { - outputBuffer.write(await this._resolveEmoji(emojiMatch, part)); - continue; - } - - outputBuffer.write(part); - } - - return outputBuffer.toString().trim(); - } - - FutureOr _resolveEmoji(RegExpMatch match, String content) async { - if (emojiTagHandling == TagHandling.ignore) { - return content; - } - - if (emojiTagHandling == TagHandling.remove) { - return ""; - } - - if (emojiTagHandling == TagHandling.sanitize) { - // TODO: check how to escape emoji properly - return "<${match.group(1)}:${match.group(2)}$_whiteSpaceCharacter:$_whiteSpaceCharacter${match.group(3)}>"; - } - - if (emojiTagHandling == TagHandling.name || emojiTagHandling == TagHandling.fullName) { - return ":${match.group(2)}:"; - } - - if (emojiTagHandling == TagHandling.nameNoPrefix || emojiTagHandling == TagHandling.fullNameNoPrefix) { - return match.group(2).toString(); - } - - return content; - } - - FutureOr _resolveChannel(RegExpMatch match, String content) async { - if (channelTagHandling == TagHandling.ignore) { - return content; - } - - if (channelTagHandling == TagHandling.remove) { - return ""; - } - - if (channelTagHandling == TagHandling.sanitize) { - return "<#$_whiteSpaceCharacter${match.group(1)}>"; - } - - final channel = _client.channels.values.firstWhere((ch) => ch is TextGuildChannel && ch.id == match.group(1)) as TextGuildChannel?; - - if (channelTagHandling == TagHandling.name || channelTagHandling == TagHandling.fullName) { - return channel != null ? "#${channel.name}" : this.missingEntityHandler("channel"); - } - - if (channelTagHandling == TagHandling.nameNoPrefix || channelTagHandling == TagHandling.fullNameNoPrefix) { - return channel != null ? channel.name : this.missingEntityHandler("channel"); - } - - return content; - } - - FutureOr _resolveEveryone(RegExpMatch match, String content) async { - if (roleTagHandling == TagHandling.remove) { - return ""; - } - - if (roleTagHandling == TagHandling.sanitize) { - return "@$_whiteSpaceCharacter${match.group(1)}"; - } - - return content; - } - - FutureOr _resolveRoleMention(RegExpMatch match, String content) async { - if (roleTagHandling == TagHandling.ignore) { - return content; - } - - if (roleTagHandling == TagHandling.remove) { - return ""; - } - - if (roleTagHandling == TagHandling.sanitize) { - return "<@&$_whiteSpaceCharacter${match.group(1)}>"; - } - - try { - final role = _client.guilds.values - .map((e) => e.roles.values) - .expand((element) => element) - .firstWhere((element) => element.id == Snowflake(match.group(1))); - - if (roleTagHandling == TagHandling.name || roleTagHandling == TagHandling.fullName) { - return "@${role.name}"; - } - - if (roleTagHandling == TagHandling.nameNoPrefix || roleTagHandling == TagHandling.fullNameNoPrefix) { - return role.name; - } - } on Exception { - return this.missingEntityHandler("role"); - } - - return content; - } - - FutureOr _resoleUserMention(RegExpMatch match, String content) async { - if (userTagHandling == TagHandling.ignore) { - return content; - } - - if (userTagHandling == TagHandling.remove) { - return ""; - } - - if (userTagHandling == TagHandling.sanitize) { - return "<@$_whiteSpaceCharacter${match.group(1)}>"; - } - - final user = _client.users[Snowflake(match.group(1))]; - - if (userTagHandling == TagHandling.name) { - return user != null ? "@${user.username}" : this.missingEntityHandler("user"); - } - - if (userTagHandling == TagHandling.nameNoPrefix) { - return user != null ? user.username : this.missingEntityHandler("user"); - } - - if (userTagHandling == TagHandling.fullName) { - return user != null ? "@${user.tag}" : this.missingEntityHandler("user"); - } - - if (userTagHandling == TagHandling.fullNameNoPrefix) { - return user != null ? "${user.tag}" : this.missingEntityHandler("user"); - } - - return ""; - } -} - -FutureOr _defaultMissingEntityHandler(String entityType) { - switch (entityType) { - case "user": - return "[Could not get user]"; - case "role": - return "[Could not get role]"; - case "channel": - return "[Could not get channel]"; - default: - return ""; - } -} diff --git a/nyxx_extensions/lib/src/utils.dart b/nyxx_extensions/lib/src/utils.dart deleted file mode 100644 index 4f4b6431a..000000000 --- a/nyxx_extensions/lib/src/utils.dart +++ /dev/null @@ -1,40 +0,0 @@ -import "dart:async"; - -// ignore: public_member_api_docs -class StreamUtils { - /// Merges list of stream into one stream - static Stream merge(List> streams) { - var _open = streams.length; - final streamController = StreamController(); - for (final stream in streams) { - stream.listen(streamController.add) - ..onError(streamController.addError) - ..onDone(() { - if (--_open == 0) { - streamController.close(); - } - }); - } - return streamController.stream; - } -} - -// ignore: public_member_api_docs -class StringUtils { - /// Splits string based on desired length - static Iterable split(String str, int length) sync* { - var last = 0; - while (last < str.length && ((last + length) < str.length)) { - yield str.substring(last, last + length); - last += length; - } - yield str.substring(last, str.length); - } - - /// Splits string based on number of wanted substrings - static Iterable splitEqually(String str, int pieces) { - final len = (str.length / pieces).round(); - - return split(str, len); - } -} diff --git a/nyxx_extensions/lib/utils.dart b/nyxx_extensions/lib/utils.dart deleted file mode 100644 index d2bfae5d5..000000000 --- a/nyxx_extensions/lib/utils.dart +++ /dev/null @@ -1 +0,0 @@ -export "src/utils.dart"; diff --git a/nyxx_extensions/pubspec.yaml b/nyxx_extensions/pubspec.yaml deleted file mode 100644 index 35d4565fb..000000000 --- a/nyxx_extensions/pubspec.yaml +++ /dev/null @@ -1,17 +0,0 @@ -name: nyxx_extensions -version: 2.0.1 -description: Nyxx Extensions Module. Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. -homepage: https://github.com/nyxx-discord/nyxx -repository: https://github.com/nyxx-discord/nyxx -documentation: https://nyxx.l7ssha.xyz -issue_tracker: https://github.com/nyxx-discord/nyxx/issues - -environment: - sdk: '>=2.13.0 <3.0.0' - -dependencies: - http: "^0.13.3" - nyxx: "^2.0.0" - -dev_dependencies: - test: "^1.17.0" diff --git a/nyxx_extensions/test/unit.dart b/nyxx_extensions/test/unit.dart deleted file mode 100644 index e3cb473e6..000000000 --- a/nyxx_extensions/test/unit.dart +++ /dev/null @@ -1,153 +0,0 @@ -import "dart:async"; - -import "package:nyxx/nyxx.dart"; -import "package:nyxx_extensions/embedbuilder_extension.dart"; -import "package:nyxx_extensions/emoji.dart"; -import "package:nyxx_extensions/src/utils.dart"; -import "package:test/expect.dart"; -import "package:test/scaffolding.dart"; - -void main() async { - test("Basic tests", () async { - final emojis = await getAllEmojiDefinitions(cache: true).toList(); - expect(emojis, isNotEmpty); - - final emojisFromCache = await getAllEmojiDefinitions().toList(); - expect(emojisFromCache, isNotEmpty); - }); - - group("Embed Builder from Json", () { - test("Embed Footer Builder test", () async { - final data = { - "text": "Footer Text", - "icon_url": "https://cdn.discordapp.com/avatars/281314080923320321/e7e716c1a1efb236f9ff0e29a54f1ba2.png?size=128", - }; - final footer = EmbedFooterBuilder().importJson(data); - - expect(footer.text, equals("Footer Text")); - expect(footer.iconUrl, equals("https://cdn.discordapp.com/avatars/281314080923320321/e7e716c1a1efb236f9ff0e29a54f1ba2.png?size=128")); - }); - - test("Embed Author Builder test", () async { - final data = { - "name": "HarryET", - "url": "https://discord.com", - "icon_url": "https://cdn.discordapp.com/avatars/281314080923320321/e7e716c1a1efb236f9ff0e29a54f1ba2.png?size=128", - }; - final author = EmbedAuthorBuilder().importJson(data); - - expect(author.name, equals("HarryET")); - expect(author.url, equals("https://discord.com")); - expect(author.iconUrl, equals("https://cdn.discordapp.com/avatars/281314080923320321/e7e716c1a1efb236f9ff0e29a54f1ba2.png?size=128")); - }); - - group("Embed Field Builder tests", () { - test("with inline", () async { - final data = { - "name": "Example", - "value": "This is an example text", - "inline": true - }; - final field = EmbedFieldBuilder().importJson(data); - - expect(field.name, equals("Example")); - expect(field.content, equals("This is an example text")); - expect(field.inline, equals(true)); - }); - - test("without inline", () async { - final data = { - "name": "Example", - "value": "This is an example text", - }; - final field = EmbedFieldBuilder().importJson(data); - - expect(field.name, equals("Example")); - expect(field.content, equals("This is an example text")); - expect(field.inline, isNull); - }); - - test("accept empty values", () async { - final data = { - "name": "Example", - "value": null, - "inline": true - }; - final field = EmbedFieldBuilder().importJson(data); - - expect(field.name, isNotEmpty); - expect(field.content, isNull); - }); - }); - - test("Create embed from json", () async { - final data = { - "title": "title ~~(did you know you can have markdown here too?)~~", - "description": "this supports [named links](https://discordapp.com) on top of the previously shown subset of markdown. ```\nyes, even code blocks```", - "url": "https://discordapp.com", - "color": 14515245, - "timestamp": "2021-06-05T10:02:06.400Z", - "footer": { - "icon_url": "https://cdn.discordapp.com/embed/avatars/0.png", - "text": "footer text" - }, - "thumbnail": { - "url": "https://cdn.discordapp.com/embed/avatars/0.png" - }, - "image": { - "url": "https://cdn.discordapp.com/embed/avatars/0.png" - }, - "author": { - "name": "author name", - "url": "https://discordapp.com", - "icon_url": "https://cdn.discordapp.com/embed/avatars/0.png" - }, - "fields": [ - { - "name": "🤔", - "value": "some of these properties have certain limits...", - "inline": false - }, - { - "name": "<:thonkang:219069250692841473>", - "value": "are inline fields", - "inline": true - } - ] - }; - final embed = EmbedBuilder().importJson(data); - expect(BuilderUtility.buildRawEmbed(embed), equals(data)); - }); - }); - - group("Utils tests", () { - test("StreamUtils.merge test", () { - final streamController1 = StreamController.broadcast(); - final stream1 = streamController1.stream; - - final streamController2 = StreamController.broadcast(); - final stream2 = streamController2.stream; - - final combinedStream = StreamUtils.merge([stream1, stream2]); - - expect(combinedStream, emitsInOrder([1, 2, 3])); - - streamController1.add(1); - streamController2.add(2); - streamController2.add(3); - - streamController1.close(); - streamController2.close(); - }); - - test("StringUtils.split", () { - const str = "Five Five Five"; - expect(["Five ", "Five ", "Five"], StringUtils.split(str, 5)); - }); - - test("StringUtils.splitEqually", () { - const str = "Five"; - expect(["Fi", "ve"], StringUtils.splitEqually(str, 2)); - }); - }); -} diff --git a/nyxx_interactions/CHANGELOG.md b/nyxx_interactions/CHANGELOG.md deleted file mode 100644 index c7945a276..000000000 --- a/nyxx_interactions/CHANGELOG.md +++ /dev/null @@ -1,38 +0,0 @@ -## 2.0.2 -_15.10.2021_ - -- Move to Apache 2 license - -## 2.0.1 -_03.10.2021_ - -- fix deserialization of autocomplete interaction - -## 2.0.0 -_03.10.2021_ - -> Bumped version to 2.0 for compatibility with nyxx - -- Interactions (Slash command) initial implementation (3128388) @HarryET -- Implementation of ephemeral attachments -- Implementation of context menus -- Implementation of message components - ---- - -- Implemented Commander like interface (8fae519) -- Added `subCommand` property to InteractionEvent to ease out recognizing subcommands (5b30b29) - - -## 2.0.0-rc.4 -_21.04.2021_ - -> **Release Candidate 2 for stable version. Requires dart sdk 2.12** - - - Interactions (Slash command) initial implementation (3128388) @HarryET - - Implemented Commander like interface (8fae519) - - Added `subCommand` property to InteractionEvent to ease out recognizing subcommands (5b30b29) - -## 1.1-dev.1 - - - Initial version @HarryET diff --git a/nyxx_interactions/LICENSE b/nyxx_interactions/LICENSE deleted file mode 100644 index 035f3247d..000000000 --- a/nyxx_interactions/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 Harry Bairstow, Szymon Uglis and contributors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/nyxx_interactions/README.md b/nyxx_interactions/README.md deleted file mode 100644 index 139a4fa31..000000000 --- a/nyxx_interactions/README.md +++ /dev/null @@ -1,102 +0,0 @@ -# nyxx_interactions - -[![pub](https://img.shields.io/pub/v/nyxx.svg)](https://pub.dartlang.org/packages/nyxx) -[![documentation](https://img.shields.io/badge/Documentation-nyxx-yellow.svg)](https://www.dartdocs.org/documentation/nyxx/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.commander-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.commander/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.interactions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.interactions/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.extentions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.extensions/latest/) - -Simple, robust framework for creating discord bots for Dart language. - -
- -### Features - -- **Slash commands support**
- Supports and provides easy API for creating and handling slash commands -- **Commands framework included**
- A fast way to create a bot with command support. Implementing the framework is simple - and everything is done automatically. -- **Cross Platform**
- Nyxx works on the command line, in the browser, and on mobile devices. -- **Fine Control**
- Nyxx allows you to control every outgoing HTTP request or WebSocket message. -- **Complete**
- Nyxx supports nearly all Discord API endpoints. - - -## Quick example - -Basic usage: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - bot.onMessageReceived.listen((event) { - if (event.message.content == "!ping") { - event.message.channel.sendMessage(MessageBuilder.content("Pong!")); - } - }); -} -``` - -Slash commands: -```dart -void main() { - final bot = Nyxx("<%TOKEN%>", GatewayIntents.allUnprivileged); - final interactions = Interactions(bot); - - interactions - ..registerHandler("test", "This is test comamnd", [], handler: (event) async { - await event.reply(MessageBuilder.content("This is example message result")); - }); -} -``` - -Commands: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - Commander(bot, prefix: "!!!") - ..registerCommand("ping", (context, message) => context.reply(MessageBuilder.content("Pong!"))); -} -``` - -## More examples - -Nyxx examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx/example). - -Commander examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx_commander/example) - -Slash commands (interactions) examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx_interactions/example) - -### Example bots -- [Running on Dart](https://github.com/l7ssha/running_on_dart) - -## Documentation, help and examples - -**Dartdoc documentation is hosted on [pub](https://www.dartdocs.org/documentation/nyxx/latest/). -This wiki just fills gap in docs with more descriptive guides and tutorials.** - -#### [Discord API docs](https://discordapp.com/developers/docs/intro) -Discord API documentation features rich descriptions about all topics that nyxx covers. - -#### [Discord API Guild](https://discord.gg/discord-api) -The unofficial guild for Discord Bot developers. To get help with nyxx check `#dart_nyxx` channel. - -#### [Dartdocs](https://www.dartdocs.org/documentation/nyxx/latest/) -The dartdocs page will always have the documentation for the latest release. - -#### [Dev docs](https://nyxx.l7ssha.xyz) -You can read about upcoming changes in the library on my website. - -#### [Wiki](https://github.com/l7ssha/nyxx/wiki) -Wiki documentation are designed to match the latest Nyxx release. - -## Contributing to Nyxx - -Read [contributing document](https://github.com/l7ssha/nyxx/blob/development/CONTRIBUTING.md) - -## Credits - -* [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx). diff --git a/nyxx_interactions/analysis_options.yaml b/nyxx_interactions/analysis_options.yaml deleted file mode 100644 index 623030589..000000000 --- a/nyxx_interactions/analysis_options.yaml +++ /dev/null @@ -1,106 +0,0 @@ -analyzer: - strong-mode: - implicit-casts: false -linter: - rules: - - avoid_empty_else - - comment_references - - control_flow_in_finally - - empty_statements - - hash_and_equals - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - avoid_slow_async_io - - cancel_subscriptions - - test_types_in_equals - - throw_in_finally - - valid_regexps - - always_declare_return_types - - annotate_overrides - - avoid_init_to_null - - avoid_return_types_on_setters - - await_only_futures - - camel_case_types - - constant_identifier_names - - empty_constructor_bodies - - library_names - - library_prefixes - - non_constant_identifier_names - - only_throw_errors - - package_api_docs - - package_prefixed_library_names - - prefer_is_not_empty - - slash_for_doc_comments - - type_init_formals - - unnecessary_getters_setters - - package_names - - unnecessary_await_in_return - - use_function_type_syntax_for_parameters - - avoid_returning_null_for_future - - no_duplicate_case_values - - unnecessary_statements - - always_require_non_null_named_parameters - - always_put_required_named_parameters_first - - avoid_catches_without_on_clauses - - avoid_function_literals_in_foreach_calls - - avoid_redundant_argument_values - - avoid_returning_null - - avoid_returning_null_for_void - - avoid_returning_this - - camel_case_extensions - - curly_braces_in_flow_control_structures - - directives_ordering - - empty_catches - - join_return_with_assignment - - leading_newlines_in_multiline_strings - - missing_whitespace_between_adjacent_strings - - no_runtimeType_toString - - null_closures - - omit_local_variable_types - - one_member_abstracts - - prefer_adjacent_string_concatenation - - prefer_collection_literals - - prefer_conditional_assignment - - prefer_const_constructors - - prefer_const_constructors_in_immutables - - prefer_const_declarations - - prefer_const_literals_to_create_immutables - - prefer_constructors_over_static_methods - - prefer_contains - - prefer_double_quotes - - prefer_equal_for_default_values - - prefer_expression_function_bodies - - prefer_final_fields - - prefer_final_in_for_each - - prefer_final_locals - - prefer_for_elements_to_map_fromIterable - - prefer_foreach - - prefer_function_declarations_over_variables - - prefer_generic_function_type_aliases - - prefer_if_elements_to_conditional_expressions - - prefer_if_null_operators - - prefer_initializing_formals - - prefer_inlined_adds - - prefer_int_literals - - prefer_interpolation_to_compose_strings - - prefer_is_empty - - provide_deprecation_message - - prefer_typing_uninitialized_variables - - public_member_api_docs - - unawaited_futures - - unnecessary_brace_in_string_interps - - unnecessary_lambdas - - unnecessary_null_in_if_null_operators - - unnecessary_parenthesis - - unnecessary_raw_strings - - unnecessary_string_escapes - - use_rethrow_when_possible - - use_string_buffers - - void_checks - - use_to_and_as_if_applicable - - sort_pub_dependencies - - prefer_is_not_operator - - prefer_iterable_whereType - - prefer_mixin - - prefer_null_aware_operators - - prefer_spread_collections \ No newline at end of file diff --git a/nyxx_interactions/example/basic.dart b/nyxx_interactions/example/basic.dart deleted file mode 100644 index 2fee54ead..000000000 --- a/nyxx_interactions/example/basic.dart +++ /dev/null @@ -1,42 +0,0 @@ -import "dart:math"; - -import "package:nyxx/nyxx.dart"; -import "package:nyxx_interactions/interactions.dart"; - -// Creates instance of slash command builder with name, description and sub options. -// Its used to synchronise commands with discord and also to be able to respond to them. -// SlashCommandBuilder allows to register handler for slash command that you will be able -// to respond to command event. -final singleCommand = SlashCommandBuilder("help", "This is example help command", []) - ..registerHandler((event) async { - // Handler accepts a function with parameter of SlashCommandInteraction which contains - // all of the stuff need to respond to interaction. - // From there you have two routes: ack and then respond later or respond immediately without ack. - // Sending ack will display indicator that bot is thinking and from there you will have 15 mins to respond to - // that interaction. - await event.respond(MessageBuilder.content("Work in progress")); - }); - -// If you want your command to have subcommand you don't need to register handler -// for main handler because only sub commands will be invokable. -// In list for options you can create new instances of sub commands with -// commands handlers that command could be responded by bot. -final subCommand = SlashCommandBuilder("game", "This is example game command", [ - subCommandFlipGame -]); - -// Subcommand event handler receives same SlashCommandInteraction parameter with all -// info and tools need to respond to an interaction -final subCommandFlipGame = CommandOptionBuilder(CommandOptionType.subCommand, "coinflip", "Coin flip game") - ..registerHandler((event) async { - final result = Random().nextBool() ? "tail" : "heads"; - - await event.respond(MessageBuilder.content("You flipped: $result")); - }); - -void main() { - final bot = Nyxx("", GatewayIntents.allUnprivileged); - Interactions(bot) - ..registerSlashCommand(singleCommand) // Register created before slash command - ..syncOnReady(); // This is needed if you want to sync commands on bot startup. -} diff --git a/nyxx_interactions/example/buttons-and-dropdowns.dart b/nyxx_interactions/example/buttons-and-dropdowns.dart deleted file mode 100644 index 8ace1a5b3..000000000 --- a/nyxx_interactions/example/buttons-and-dropdowns.dart +++ /dev/null @@ -1,65 +0,0 @@ -import "package:nyxx/nyxx.dart"; -import "package:nyxx_interactions/interactions.dart"; - -final singleCommand = SlashCommandBuilder("help", "This is example help command", []) - ..registerHandler((event) async { - // All "magic" happens via ComponentMessageBuilder class that extends MessageBuilder - // from main nyxx package. This new builder allows to create message with components. - final componentMessageBuilder = ComponentMessageBuilder(); - - // There are two types of button - regular ones that can be responded to an interaction - // and url button that only redirects to specified url. - // Here we are focusing on regular button that we can respond to. - // Label is what user will see on button, customId is id that we ca use later to - // catch button event and respond to, and style is what kind of button we want create. - // - // Adding selects is as easy as adding buttons. Use MultiselectBuilder with custom id - // and list of multiselect options. - final componentRow = ComponentRowBuilder() - ..addComponent(ButtonBuilder("This is button label", "thisisid", ComponentStyle.success)) - ..addComponent(ButtonBuilder("This is another button", "thisisid2", ComponentStyle.success)) - ..addComponent(MultiselectBuilder("customId", [ - MultiselectOptionBuilder("example option 1", "option1"), - MultiselectOptionBuilder("example option 2", "option2"), - MultiselectOptionBuilder("example option 3", "option3"), - ])); - - // Then component row can be added to message builder and sent to user. - componentMessageBuilder.addComponentRow(componentRow); - await event.respond(componentMessageBuilder); - }); - -// To handle button interaction you need need function that accepts -// ButtonInteractionEvent as parameter. Since button event is interaction like -// slash command it needs to acknowledged and/or responded. -// If you know that command handler would take more that 3 second to complete -// you would need to acknowledge and then respond later with proper result. -Future buttonHandler(ButtonInteractionEvent event) async { - await event.acknowledge(); // ack the interaction so we can send response later - - // Send followup to button click with id of button - await event.sendFollowup(MessageBuilder.content( - "Button presed with id: ${event.interaction.customId}") - ); -} - -// Handling multiselect events is no different from handling button. -// Only thing that changes is type of function argument -- it now passes information -// about values selected with multiselect -Future multiselectHandlerHandler(MultiselectInteractionEvent event) async { - await event.acknowledge(); // ack the interaction so we can send response later - - // Send followup to button click with id of button - await event.sendFollowup(MessageBuilder.content( - "Options chosen with values: ${event.interaction.values}") - ); -} - -void main() { - final bot = Nyxx("", GatewayIntents.allUnprivileged); - Interactions(bot) - ..registerSlashCommand(singleCommand) // Register created before slash command - ..registerButtonHandler("thisisid", buttonHandler) // register handler for button with id: thisisid - ..registerMultiselectHandler("customId", multiselectHandlerHandler) // register handler for multiselect with id: customId - ..syncOnReady(); // This is needed if you want to sync commands on bot startup. -} diff --git a/nyxx_interactions/example/example.dart b/nyxx_interactions/example/example.dart deleted file mode 100644 index f8d706a92..000000000 --- a/nyxx_interactions/example/example.dart +++ /dev/null @@ -1,13 +0,0 @@ -import "package:nyxx/nyxx.dart"; -import "package:nyxx_interactions/interactions.dart"; - -void main() { - final bot = Nyxx("", GatewayIntents.allUnprivileged); - Interactions(bot) - ..registerSlashCommand( - SlashCommandBuilder("itest", "This is test command", [ - CommandOptionBuilder(CommandOptionType.subCommand, "subtest", "This is sub test") - ..registerHandler((event) => event.respond(MessageBuilder.content("This is example command"))) - ], guild: 302360552993456135.toSnowflake()) - )..syncOnReady(); -} diff --git a/nyxx_interactions/lib/interactions.dart b/nyxx_interactions/lib/interactions.dart deleted file mode 100644 index 316a49d26..000000000 --- a/nyxx_interactions/lib/interactions.dart +++ /dev/null @@ -1,46 +0,0 @@ -library nyxx_interactions; - -import "dart:async"; -import "dart:collection"; -import "dart:convert"; -import "dart:io"; - -import "package:crypto/crypto.dart"; -import "package:logging/logging.dart"; -import "package:nyxx/nyxx.dart"; - -// Root -part "src/Interactions.dart"; -// Builders -part "src/builders/ArgChoiceBuilder.dart"; -part "src/builders/CommandOptionBuilder.dart"; -part "src/builders/CommandPermissionBuilder.dart"; -part "src/builders/ComponentBuilder.dart"; -part "src/builders/SlashCommandBuilder.dart"; -// Events -part "src/events/InteractionEvent.dart"; -part "src/exceptions/AlreadyResponded.dart"; -// Exceptions -part "src/exceptions/InteractionExpired.dart"; -part "src/exceptions/ResponseRequired.dart"; -// Internal -part "src/internal/_EventController.dart"; -part "src/internal/InteractionEndpoints.dart"; -// Sync -part "src/internal/sync/ICommandsSync.dart"; -part "src/internal/sync/LockFileCommandSync.dart"; -part "src/internal/sync/ManualCommandSync.dart"; -// Utils -part "src/internal/utils.dart"; -// Command Args -part "src/models/ArgChoice.dart"; -part "src/models/CommandOption.dart"; -part "src/models/Interaction.dart"; -part "src/models/InteractionDataResolved.dart"; -part "src/models/InteractionOption.dart"; -// Models -part "src/models/SlashCommand.dart"; -part "src/models/SlashCommandType.dart"; - -/// Typedef of api response -typedef RawApiMap = Map; diff --git a/nyxx_interactions/lib/src/Interactions.dart b/nyxx_interactions/lib/src/Interactions.dart deleted file mode 100644 index a0a252555..000000000 --- a/nyxx_interactions/lib/src/Interactions.dart +++ /dev/null @@ -1,279 +0,0 @@ -part of nyxx_interactions; - -/// Function that will handle execution of slash command interaction event -typedef SlashCommandHandler = FutureOr Function(SlashCommandInteractionEvent); - -/// Function that will handle execution of button interaction event -typedef ButtonInteractionHandler = FutureOr Function(ButtonInteractionEvent); - -/// Function that will handle execution of dropdown event -typedef MultiselectInteractionHandler = FutureOr Function(MultiselectInteractionEvent); - -/// Function that will handle execution of button interaction event -typedef AutocompleteInteractionHandler = FutureOr Function(AutocompleteInteractionEvent); - -/// Interaction extension for Nyxx. Allows use of: Slash Commands. -class Interactions { - static const _interactionCreateCommand = "INTERACTION_CREATE"; - - late final _EventController _events; - final Logger _logger = Logger("Interactions"); - - /// Reference to client - final Nyxx _client; - - final _commandBuilders = []; - final _commands = []; - final _commandHandlers = {}; - final _buttonHandlers = {}; - final _autocompleteHandlers = {}; - final _multiselectHandlers = {}; - - /// Commands registered by bot - Iterable get commands => UnmodifiableListView(this._commands); - - /// Emitted when a slash command is sent. - late final Stream onSlashCommand; - - /// Emitted when a button interaction is received. - late final Stream onButtonEvent; - - /// Emitted when a dropdown interaction is received. - late final Stream onMultiselectEvent; - - /// Emitted when a slash command is created by the user. - late final Stream onSlashCommandCreated; - - /// Emitted when a slash command is created by the user. - late final Stream onAutocompleteEvent; - - /// All interaction endpoints that can be accessed. - late final IInteractionsEndpoints interactionsEndpoints; - - /// Create new instance of the interactions class. - Interactions(this._client) { - _events = _EventController(this); - _client.options.dispatchRawShardEvent = true; - this.interactionsEndpoints = _InteractionsEndpoints(_client); - - _logger.info("Interactions ready"); - - _client.onReady.listen((event) async { - _client.shardManager.rawEvent.listen((event) { - if (event.rawData["op"] == OPCodes.dispatch && event.rawData["t"] == _interactionCreateCommand) { - this._logger.fine("Received interaction event: [${event.rawData}]"); - - final type = event.rawData["d"]["type"] as int; - - switch (type) { - case 2: - _events.onSlashCommand.add(SlashCommandInteractionEvent._new(this, event.rawData["d"] as RawApiMap)); - break; - case 3: - final componentType = event.rawData["d"]["data"]["component_type"] as int; - - switch (componentType) { - case 2: - _events.onButtonEvent - .add(ButtonInteractionEvent._new(this, event.rawData["d"] as Map)); - break; - case 3: - _events.onMultiselectEvent - .add(MultiselectInteractionEvent._new(this, event.rawData["d"] as Map)); - break; - default: - this - ._logger - .warning("Unknown componentType type: [$componentType]; Payload: ${jsonEncode(event.rawData)}"); - } - break; - case 4: - _events.onAutocompleteEvent - .add(AutocompleteInteractionEvent._new(this, event.rawData["d"] as Map)); - break; - default: - this._logger.warning("Unknown interaction type: [$type]; Payload: ${jsonEncode(event.rawData)}"); - } - } - }); - }); - } - - /// Syncs commands builders with discord after client is ready. - void syncOnReady({ICommandsSync syncRule = const ManualCommandSync()}) { - this._client.onReady.listen((_) async { - await this.sync(syncRule: syncRule); - }); - } - - /// Syncs command builders with discord immediately. - /// Warning: Client could not be ready at the function execution. - /// Use [syncOnReady] for proper behavior - Future sync({ICommandsSync syncRule = const ManualCommandSync()}) async { - if (!await syncRule.shouldSync(this._commandBuilders)) { - return; - } - - final commandPartition = _partition(this._commandBuilders, (element) => element.guild == null); - final globalCommands = commandPartition.first; - final groupedGuildCommands = _groupSlashCommandBuilders(commandPartition.last); - - final globalCommandsResponse = await this.interactionsEndpoints - .bulkOverrideGlobalCommands(this._client.app.id, globalCommands) - .toList(); - - _extractCommandIds(globalCommandsResponse); - this._registerCommandHandlers(globalCommandsResponse, globalCommands); - - for(final entry in groupedGuildCommands.entries) { - final response = await this.interactionsEndpoints - .bulkOverrideGuildCommands(this._client.app.id, entry.key, entry.value) - .toList(); - - _extractCommandIds(response); - this._registerCommandHandlers(response, entry.value); - await this.interactionsEndpoints.bulkOverrideGuildCommandsPermissions(this._client.app.id, entry.key, entry.value); - } - - this._commandBuilders.clear(); // Cleanup after registering command since we don't need this anymore - this._logger.info("Finished bulk overriding slash commands and permissions"); - - if (this._commands.isNotEmpty) { - this.onSlashCommand.listen((event) async { - final commandHash = _determineInteractionCommandHandler(event.interaction); - - this._logger.info("Executing command with hash [$commandHash]"); - if (this._commandHandlers.containsKey(commandHash)) { - await this._commandHandlers[commandHash]!(event); - } - }); - - this._logger.info("Finished registering ${this._commandHandlers.length} commands!"); - } - - if (this._buttonHandlers.isNotEmpty) { - this.onButtonEvent.listen((event) { - if (this._buttonHandlers.containsKey(event.interaction.customId)) { - this._logger.info("Executing button with id [${event.interaction.customId}]"); - this._buttonHandlers[event.interaction.customId]!(event); - } else { - this._logger.warning("Received event for unknown button: ${event.interaction.customId}"); - } - }); - } - - if (this._multiselectHandlers.isNotEmpty) { - this.onMultiselectEvent.listen((event) { - if (this._multiselectHandlers.containsKey(event.interaction.customId)) { - this._logger.info("Executing multiselect with id [${event.interaction.customId}]"); - this._multiselectHandlers[event.interaction.customId]!(event); - } else { - this._logger.warning("Received event for unknown dropdown: ${event.interaction.customId}"); - } - }); - } - - if (this._autocompleteHandlers.isNotEmpty) { - this.onAutocompleteEvent.listen((event) { - final name = event.focusedOption.name; - - if (this._autocompleteHandlers.containsKey(name)) { - this._logger.info("Executing autocomplete with id [$name]"); - this._autocompleteHandlers[name]!(event); - } else { - this._logger.warning("Received event for unknown dropdown: $name"); - } - }); - } - } - - /// Registers callback for button event for given [id] - void registerAutocompleteHandler(String id, AutocompleteInteractionHandler handler) => this._autocompleteHandlers[id] = handler; - - /// Registers callback for button event for given [id] - void registerButtonHandler(String id, ButtonInteractionHandler handler) => this._buttonHandlers[id] = handler; - - /// Register callback for dropdown event for given [id] - void registerMultiselectHandler(String id, MultiselectInteractionHandler handler) => - this._multiselectHandlers[id] = handler; - - /// Allows to register new [SlashCommandBuilder] - void registerSlashCommand(SlashCommandBuilder slashCommandBuilder) => this._commandBuilders.add(slashCommandBuilder); - - /// Register callback for slash command event for given [id] - void registerSlashCommandHandler(String id, SlashCommandHandler handler) => - this._commandHandlers[id] = handler; - - /// Deletes global command - Future deleteGlobalCommand(Snowflake commandId) => - this.interactionsEndpoints.deleteGlobalCommand(this._client.app.id, commandId); - - /// Deletes guild command - Future deleteGuildCommand(Snowflake commandId, Snowflake guildId) => - this.interactionsEndpoints.deleteGuildCommand(this._client.app.id, commandId, guildId); - - /// Fetches all global bots command - Stream fetchGlobalCommands() => - this.interactionsEndpoints.fetchGlobalCommands(this._client.app.id); - - /// Fetches all guild commands for given guild - Stream fetchGuildCommands(Snowflake guildId) => - this.interactionsEndpoints.fetchGuildCommands(this._client.app.id, guildId); - - void _extractCommandIds(List commands) { - for (final slashCommand in commands) { - this._commandBuilders - .firstWhere((element) => element.name == slashCommand.name && element.guild == slashCommand.guild?.id) - ._setId(slashCommand.id); - } - } - - void _registerCommandHandlers(List registeredSlashCommands, Iterable builders) { - for(final registeredCommand in registeredSlashCommands) { - final matchingBuilder = - builders.firstWhere((element) => element.name.toLowerCase() == registeredCommand.name.toLowerCase()); - this._assignCommandToHandler(matchingBuilder, registeredCommand); - - this._commands.add(registeredCommand); - } - } - - void _assignCommandToHandler(SlashCommandBuilder builder, SlashCommand command) { - final commandHashPrefix = "${command.id}|${command.name}"; - - final subCommands = builder.options.where((element) => element.type == CommandOptionType.subCommand); - if (subCommands.isNotEmpty) { - for (final subCommand in subCommands) { - if (subCommand._handler == null) { - continue; - } - - this._commandHandlers["$commandHashPrefix|${subCommand.name}"] = subCommand._handler!; - } - - return; - } - - final subCommandGroups = builder.options.where((element) => element.type == CommandOptionType.subCommandGroup); - if (subCommandGroups.isNotEmpty) { - for (final subCommandGroup in subCommandGroups) { - final subCommands = - subCommandGroup.options?.where((element) => element.type == CommandOptionType.subCommand) ?? []; - - for (final subCommand in subCommands) { - if (subCommand._handler == null) { - continue; - } - - this._commandHandlers["$commandHashPrefix|${subCommandGroup.name}|${subCommand.name}"] = subCommand._handler!; - } - } - - return; - } - - if (builder._handler != null) { - this._commandHandlers[commandHashPrefix] = builder._handler!; - } - } -} diff --git a/nyxx_interactions/lib/src/builders/ArgChoiceBuilder.dart b/nyxx_interactions/lib/src/builders/ArgChoiceBuilder.dart deleted file mode 100644 index a872a22bd..000000000 --- a/nyxx_interactions/lib/src/builders/ArgChoiceBuilder.dart +++ /dev/null @@ -1,20 +0,0 @@ -part of nyxx_interactions; - -/// A specified choice for a slash command argument. -class ArgChoiceBuilder extends Builder { - /// This options name. - String name; - - /// This is the options value, must be int or string - dynamic value; - - /// A Choice for the user to input in int & string args. - /// You can only have an int or string option. - ArgChoiceBuilder(this.name, this.value) { - if (value is! int && value is! String) { - throw ArgumentError("Value could be either String or int type"); - } - } - - RawApiMap build() => { "name": this.name, "value": this.value }; -} diff --git a/nyxx_interactions/lib/src/builders/CommandOptionBuilder.dart b/nyxx_interactions/lib/src/builders/CommandOptionBuilder.dart deleted file mode 100644 index 250b25e3b..000000000 --- a/nyxx_interactions/lib/src/builders/CommandOptionBuilder.dart +++ /dev/null @@ -1,70 +0,0 @@ -part of nyxx_interactions; - -/// An argument for a [SlashCommandBuilder]. -class CommandOptionBuilder extends Builder { - /// The type of arg that will be later changed to an INT value, their values can be seen in the table below: - /// | Name | Value | - /// |-------------------|-------| - /// | SUB_COMMAND | 1 | - /// | SUB_COMMAND_GROUP | 2 | - /// | STRING | 3 | - /// | INTEGER | 4 | - /// | BOOLEAN | 5 | - /// | USER | 6 | - /// | CHANNEL | 7 | - /// | ROLE | 8 | - final CommandOptionType type; - - /// The name of your argument / sub-group. - final String name; - - /// The description of your argument / sub-group. - final String description; - - /// If this should be the fist required option the user picks - bool defaultArg = false; - - /// If this argument is required - bool required = false; - - /// Choices for [CommandOptionType.string] and [CommandOptionType.string] types for the user to pick from - List? choices; - - /// If the option is a subcommand or subcommand group type, this nested options will be the parameters - List? options; - - /// If [type] is channel then list can be used to restrict types of channel to choose from - List? channelTypes; - - /// Set to true if option should be autocompleted - bool? autoComplete; - - SlashCommandHandler? _handler; - - /// Used to create an argument for a [SlashCommandBuilder]. - CommandOptionBuilder(this.type, this.name, this.description, - {this.defaultArg = false, this.required = false, this.choices, this.options, - this.channelTypes, this.autoComplete}); - - /// Registers handler for subcommand - void registerHandler(SlashCommandHandler handler) { - if (this.type != CommandOptionType.subCommand) { - throw StateError("Cannot register handler for command option with type other that subcommand"); - } - - this._handler = handler; - } - - RawApiMap build() => { - "type": this.type.value, - "name": this.name, - "description": this.description, - "default": this.defaultArg, - "required": this.required, - if (this.choices != null) "choices": this.choices!.map((e) => e.build()).toList(), - if (this.options != null) "options": this.options!.map((e) => e.build()).toList(), - if (this.channelTypes != null && this.type == CommandOptionType.channel) - "channel_types": channelTypes!.map((e) => e.value).toList(), - if (this.autoComplete != null) "autocomplete": this.autoComplete, - }; -} diff --git a/nyxx_interactions/lib/src/builders/CommandPermissionBuilder.dart b/nyxx_interactions/lib/src/builders/CommandPermissionBuilder.dart deleted file mode 100644 index 91c59dd64..000000000 --- a/nyxx_interactions/lib/src/builders/CommandPermissionBuilder.dart +++ /dev/null @@ -1,46 +0,0 @@ -part of nyxx_interactions; - -/// Used to define permissions for a particular command. -abstract class ICommandPermissionBuilder extends Builder { - late final int _type; - - /// The ID of the Role or User to give permissions too - final Snowflake id; - - /// Does the role have permission to use the command - final bool hasPermission; - - ICommandPermissionBuilder(this.id, {this.hasPermission = true}); - - /// A permission for a single user that can be used in [SlashCommandBuilder] - factory ICommandPermissionBuilder.user(Snowflake id, {bool hasPermission = true}) => - UserCommandPermissionBuilder(id, hasPermission: hasPermission); - - /// A permission for a single role that can be used in [SlashCommandBuilder] - factory ICommandPermissionBuilder.role(Snowflake id, {bool hasPermission = true}) => - RoleCommandPermissionBuilder(id, hasPermission: hasPermission); -} - -/// A permission for a single role that can be used in [SlashCommandBuilder] -class RoleCommandPermissionBuilder extends ICommandPermissionBuilder { - @override - late final int _type = 1; - - /// A permission for a single role that can be used in [SlashCommandBuilder] - RoleCommandPermissionBuilder(Snowflake id, {bool hasPermission = true}) : super(id, hasPermission: hasPermission); - - @override - RawApiMap build() => {"id": this.id.toString(), "type": this._type, "permission": this.hasPermission}; -} - -/// A permission for a single user that can be used in [SlashCommandBuilder] -class UserCommandPermissionBuilder extends ICommandPermissionBuilder { - @override - late final int _type = 2; - - /// A permission for a single user that can be used in [SlashCommandBuilder] - UserCommandPermissionBuilder(Snowflake id, {bool hasPermission = true}) : super(id, hasPermission: hasPermission); - - @override - RawApiMap build() => {"id": this.id.toString(), "type": this._type, "permission": this.hasPermission}; -} diff --git a/nyxx_interactions/lib/src/builders/ComponentBuilder.dart b/nyxx_interactions/lib/src/builders/ComponentBuilder.dart deleted file mode 100644 index 5565ac625..000000000 --- a/nyxx_interactions/lib/src/builders/ComponentBuilder.dart +++ /dev/null @@ -1,231 +0,0 @@ -part of nyxx_interactions; - -/// Allows to create components -abstract class IComponentBuilder extends Builder { - /// Type of component - ComponentType get type; - - @override - Map build() => { - "type": this.type.value, - }; -} - -/// Allows to create multi select option for [MultiselectBuilder] -class MultiselectOptionBuilder extends Builder { - /// User-facing name of the option - final String label; - - /// Internal value of option - final String value; - - /// Setting to true will render this option as pre-selected - final bool isDefault; - - /// An additional description to option - String? description; - - /// Emoji displayed alongside with label - IEmoji? emoji; - - /// Creates instance of [MultiselectOptionBuilder] - MultiselectOptionBuilder(this.label, this.value, [this.isDefault = false]); - - @override - RawApiMap build() => { - "label": this.label, - "value": this.value, - "default": this.isDefault, - if (this.emoji != null) "emoji": { - if (this.emoji is IGuildEmoji) "id": (this.emoji as IGuildEmoji).id, - if (this.emoji is UnicodeEmoji) "name": (this.emoji as UnicodeEmoji).code, - if (this.emoji is GuildEmoji) "animated": (this.emoji as GuildEmoji).animated, - }, - if (description != null) "description": this.description, - }; -} - -/// Allows to create multi select interactive components. -class MultiselectBuilder extends IComponentBuilder { - @override - ComponentType get type => ComponentType.select; - - /// Max: 100 characters - final String customId; - - /// Max: 25 - final List options = []; - - /// Custom placeholder when nothing selected - String? placeholder; - - /// Minimum number of options that can be chosen. - /// Default: 1, min: 1, max: 25 - int? minValues; - - /// Maximum numbers of options that can be chosen - /// Default: 1, min: 1, max: 25 - int? maxValues; - - /// Creates instance of [MultiselectBuilder] - MultiselectBuilder(this.customId, [Iterable? options]) { - if (this.customId.length > 100) { - throw ArgumentError("Custom Id for Select cannot have more than 100 characters"); - } - - if (options != null) { - this.options.addAll(options); - } - } - - /// Adds option to dropdown - void addOption(MultiselectOptionBuilder builder) => this.options.add(builder); - - @override - Map build() => { - ...super.build(), - "custom_id": this.customId, - "options": [ - for (final optionBuilder in this.options) - optionBuilder.build() - ], - if (placeholder != null) "placeholder": this.placeholder, - if (minValues != null) "min_values": this.minValues, - if (maxValues != null) "max_values": this.maxValues, - }; -} - -/// Allows to build button. Generic interface for all types of buttons -abstract class IButtonBuilder extends IComponentBuilder { - @override - ComponentType get type => ComponentType.button; - - /// Label for button. Max 80 characters. - final String label; - - /// Style of button. See [ComponentStyle] - final ComponentStyle style; - - /// True if emoji is disabled - bool disabled = false; - - /// Additional emoji for button - IEmoji? emoji; - - /// Creates instance of [IButtonBuilder] - IButtonBuilder(this.label, this.style, {this.disabled = false, this.emoji}) { - if (this.label.length > 80) { - throw ArgumentError("Label for Button cannot have more than 80 characters"); - } - } - - @override - Map build() => { - ...super.build(), - "label": this.label, - "style": this.style.value, - if (this.disabled) "disabled": true, - if (this.emoji != null) "emoji": { - if (this.emoji is IGuildEmoji) "id": (this.emoji as IGuildEmoji).id, - if (this.emoji is UnicodeEmoji) "name": (this.emoji as UnicodeEmoji).code, - if (this.emoji is GuildEmoji) "animated": (this.emoji as GuildEmoji).animated, - } - }; -} - -/// Allows to create a button with link -class LinkButtonBuilder extends IButtonBuilder { - /// Url where his button should redirect - final String url; - - /// Creates instance of [LinkButtonBuilder] - LinkButtonBuilder( - String label, - this.url, - {bool disabled = false, - IEmoji? emoji - }): super(label, ComponentStyle.link, disabled: disabled, emoji: emoji - ) { - if (this.url.length > 512) { - throw ArgumentError("Url for button cannot have more than 512 characters"); - } - } - - @override - RawApiMap build() => { - ...super.build(), - "url": url - }; -} - -/// Button which will generate event when clicked. -class ButtonBuilder extends IButtonBuilder { - /// Id with optional additional metadata for button. - String customId; - - /// Creates instance of [ButtonBuilder] - ButtonBuilder( - String label, - this.customId, - ComponentStyle style, - {bool disabled = false, - IEmoji? emoji - }) : super(label, style, disabled: disabled, emoji: emoji - ) { - if (this.label.length > 100) { - throw ArgumentError("customId for button cannot have more than 100 characters"); - } - } - - @override - RawApiMap build() => { - ...super.build(), - "custom_id": customId - }; -} - -/// Helper builder to provide fluid api for building component rows -class ComponentRowBuilder { - final List _components = []; - - /// Adds component to row - void addComponent(IComponentBuilder componentBuilder) => this._components.add(componentBuilder); -} - -/// Extended [MessageBuilder] with support for buttons -class ComponentMessageBuilder extends MessageBuilder { - /// Set of buttons to attach to message. Message can only have 5 rows with 5 buttons each. - List>? components; - - /// Allows to add - void addComponentRow(ComponentRowBuilder componentRowBuilder) { - if (this.components == null) { - this.components = []; - } - - if (componentRowBuilder._components.length > 5 || componentRowBuilder._components.isEmpty) { - throw ArgumentError("Component row cannot be empty or have more than 5 components"); - } - - if (this.components!.length == 5) { - throw ArgumentError("There cannot be more that 5 rows of components"); - } - - this.components!.add(componentRowBuilder._components); - } - - @override - RawApiMap build(INyxx client) => { - ...super.build(client), - if (this.components != null) "components": [ - for (final row in this.components!) - { - "type": ComponentType.row.value, - "components": [ - for (final component in row) - component.build() - ] - } - ] - }; -} diff --git a/nyxx_interactions/lib/src/builders/SlashCommandBuilder.dart b/nyxx_interactions/lib/src/builders/SlashCommandBuilder.dart deleted file mode 100644 index 46bdc732d..000000000 --- a/nyxx_interactions/lib/src/builders/SlashCommandBuilder.dart +++ /dev/null @@ -1,78 +0,0 @@ -part of nyxx_interactions; - -/// A slash command, can only be instantiated through a method on [Interactions] -class SlashCommandBuilder extends Builder { - /// The commands ID that is defined on registration and used for permission syncing. - late final Snowflake _id; - - /// Command name to be shown to the user in the Slash Command UI - final String name; - - /// Command description shown to the user in the Slash Command UI - final String? description; - - /// If people can use the command by default or if they need permissions to use it. - final bool defaultPermissions; - - /// The guild that the slash Command is registered in. This can be null if its a global command. - Snowflake? guild; - - /// The arguments that the command takes - List options; - - /// Permission overrides for the command - List? permissions; - - /// Target of slash command if different that SlashCommandTarget.chat - slash command will - /// become context menu in appropriate context - SlashCommandType type; - - /// Handler for SlashCommandBuilder - SlashCommandHandler? _handler; - - /// A slash command, can only be instantiated through a method on [Interactions] - SlashCommandBuilder(this.name, this.description, this.options, - {this.defaultPermissions = true, this.permissions, this.guild, this.type = SlashCommandType.chat}) { - if (!slashCommandNameRegex.hasMatch(this.name)) { - throw ArgumentError("Command name has to match regex: ${slashCommandNameRegex.pattern}"); - } - - if (this.description == null && this.type == SlashCommandType.chat) { - throw ArgumentError("Normal slash command needs to have description"); - } - - if (this.description != null && this.type != SlashCommandType.chat) { - throw ArgumentError("Context menus cannot have description"); - } - } - - @override - RawApiMap build() => { - "name": this.name, - if (this.type == SlashCommandType.chat) "description": this.description, - "default_permission": this.defaultPermissions, - if (this.options.isNotEmpty) "options": this.options.map((e) => e.build()).toList(), - "type": this.type.value, - }; - - void _setId(Snowflake id) => this._id = id; - - /// Register a permission - void addPermission(ICommandPermissionBuilder permission) { - if (this.permissions == null) { - this.permissions = []; - } - this.permissions!.add(permission); - } - - /// Registers handler for command. Note command cannot have handler if there are options present - void registerHandler(SlashCommandHandler handler) { - if (this.options.any((element) => - element.type == CommandOptionType.subCommand || element.type == CommandOptionType.subCommandGroup)) { - throw new ArgumentError( - "Cannot register handler for slash command if command have subcommand or subcommandgroup"); - } - - this._handler = handler; - } -} diff --git a/nyxx_interactions/lib/src/events/InteractionEvent.dart b/nyxx_interactions/lib/src/events/InteractionEvent.dart deleted file mode 100644 index 001388861..000000000 --- a/nyxx_interactions/lib/src/events/InteractionEvent.dart +++ /dev/null @@ -1,209 +0,0 @@ -part of nyxx_interactions; - -abstract class InteractionEvent { - /// Reference to [Nyxx] - Nyxx get client => interactions._client; - - /// Reference to [Interactions] - late final Interactions interactions; - - /// The interaction data, includes the args, name, guild, channel, etc. - T get interaction; - - /// The DateTime the interaction was received by the Nyxx Client. - final DateTime receivedAt = DateTime.now(); - - final Logger _logger = Logger("Interaction Event"); - - InteractionEvent._new(this.interactions); -} - -class AutocompleteInteractionEvent extends InteractionEvent { - @override - late final SlashCommandInteraction interaction; - - AutocompleteInteractionEvent._new(Interactions interactions, RawApiMap raw): super._new(interactions) { - this.interaction = SlashCommandInteraction._new(client, raw); - } - - /// Returns focused option of autocomplete - InteractionOption get focusedOption => _extractArgs(this.interaction.options) - .firstWhere((element) => element.isFocused); - - /// Responds to interaction - Future respond(List builders) async { - if (DateTime.now().difference(this.receivedAt).inSeconds > 3) { - throw new InteractionExpiredError._3secs(); - } - - return this.interactions.interactionsEndpoints.respondToAutocomplete(this.interaction.id, this.interaction.token, builders); - } -} - -abstract class InteractionEventWithAcknowledge extends InteractionEvent { - /// If the Client has sent a response to the Discord API. Once the API was received a response you cannot send another. - bool _hasAcked = false; - - /// Opcode for acknowledging interaction - int get _acknowledgeOpCode; - - /// Opcode for responding to interaction - int get _respondOpcode; - - InteractionEventWithAcknowledge._new(Interactions interactions): super._new(interactions); - - /// Create a followup message for an Interaction - Future sendFollowup(MessageBuilder builder) async { - if (!_hasAcked) { - return Future.error(ResponseRequiredError()); - } - this._logger.fine("Sending followup for for interaction: ${this.interaction.id}"); - - return this.interactions.interactionsEndpoints.sendFollowup( - this.interaction.token, - this.client.app.id, - builder - ); - } - - /// Edits followup message - Future editFollowup(Snowflake messageId, MessageBuilder builder) => - this.interactions.interactionsEndpoints.editFollowup(this.interaction.token, this.client.app.id, messageId, builder); - - /// Deletes followup message with given id - Future deleteFollowup(Snowflake messageId) => - this.interactions.interactionsEndpoints.deleteFollowup(this.interaction.token, this.client.app.id, messageId); - - /// Deletes original response - Future deleteOriginalResponse() => - this.interactions.interactionsEndpoints.deleteOriginalResponse(this.interaction.token, this.client.app.id, this.interaction.id.toString()); - - /// Fetch followup message - Future fetchFollowup(Snowflake messageId) async => - this.interactions.interactionsEndpoints.fetchFollowup(this.interaction.token, this.client.app.id, messageId); - - /// Used to acknowledge a Interaction but not send any response yet. - /// Once this is sent you can then only send ChannelMessages. - /// You can also set showSource to also print out the command the user entered. - Future acknowledge({bool hidden = false}) async { - if (_hasAcked) { - return Future.error(AlreadyRespondedError()); - } - - if (DateTime.now().isAfter(this.receivedAt.add(const Duration(seconds: 3)))) { - return Future.error(InteractionExpiredError._3secs()); - } - - await this.interactions.interactionsEndpoints.acknowledge( - this.interaction.token, - this.interaction.id.toString(), - hidden, - this._acknowledgeOpCode - ); - - this._logger.fine("Sending acknowledge for for interaction: ${this.interaction.id}"); - - _hasAcked = true; - } - - /// Used to acknowledge a Interaction and send a response. - /// Once this is sent you can then only send ChannelMessages. - Future respond(MessageBuilder builder, {bool hidden = false}) async { - final now = DateTime.now(); - if (_hasAcked && now.isAfter(this.receivedAt.add(const Duration(minutes: 15)))) { - return Future.error(InteractionExpiredError._15mins()); - } else if (now.isAfter(this.receivedAt.add(const Duration(seconds: 3)))) { - return Future.error(InteractionExpiredError._3secs()); - } - - this._logger.fine("Sending respond for for interaction: ${this.interaction.id}"); - if (_hasAcked) { - await this.interactions.interactionsEndpoints.respondEditOriginal( - this.interaction.token, - this.client.app.id, - builder, - hidden - ); - } else { - if (!builder.canBeUsedAsNewMessage()) { - return Future.error(ArgumentError("Cannot sent message when MessageBuilder doesn't have set either content, embed or files")); - } - - await this.interactions.interactionsEndpoints.respondCreateResponse( - this.interaction.token, - this.interaction.id.toString(), - builder, - hidden, - _respondOpcode - ); - } - - _hasAcked = true; - } - - /// Returns [Message] object of original interaction response - Future getOriginalResponse() async => - this.interactions.interactionsEndpoints.fetchOriginalResponse(this.interaction.token, this.client.app.id, this.interaction.id.toString()); - - /// Edits original message response - Future editOriginalResponse(MessageBuilder builder) => - this.interactions.interactionsEndpoints.editOriginalResponse(this.interaction.token, this.client.app.id, builder); -} - -/// Event for slash commands -class SlashCommandInteractionEvent extends InteractionEventWithAcknowledge { - /// Interaction data for slash command - @override - late final SlashCommandInteraction interaction; - - @override - int get _acknowledgeOpCode => 5; - - @override - int get _respondOpcode => 4; - - /// Returns args of interaction - List get args => UnmodifiableListView(_extractArgs(this.interaction.options)); - - /// Searches for arg with [name] in this interaction - InteractionOption getArg(String name) => args.firstWhere((element) => element.name == name); - - SlashCommandInteractionEvent._new(Interactions interactions, RawApiMap raw) : super._new(interactions) { - this.interaction = SlashCommandInteraction._new(client, raw); - } -} - -/// Generic event for component interactions -abstract class ComponentInteractionEvent extends InteractionEventWithAcknowledge { - /// Interaction data for slash command - @override - late final T interaction; - - @override - int get _acknowledgeOpCode => 6; - - @override - int get _respondOpcode => 7; - - ComponentInteractionEvent._new(Interactions interactions, RawApiMap raw) : super._new(interactions); -} - -/// Interaction event for button events -class ButtonInteractionEvent extends ComponentInteractionEvent { - @override - late final ButtonInteraction interaction; - - ButtonInteractionEvent._new(Interactions interactions, RawApiMap raw) : super._new(interactions, raw) { - this.interaction = ButtonInteraction._new(client, raw); - } -} - -/// Interaction event for dropdown events -class MultiselectInteractionEvent extends ComponentInteractionEvent { - @override - late final MultiselectInteraction interaction; - - MultiselectInteractionEvent._new(Interactions interactions, RawApiMap raw) : super._new(interactions, raw) { - this.interaction = MultiselectInteraction._new(client, raw); - } -} diff --git a/nyxx_interactions/lib/src/exceptions/AlreadyResponded.dart b/nyxx_interactions/lib/src/exceptions/AlreadyResponded.dart deleted file mode 100644 index 9e84b483b..000000000 --- a/nyxx_interactions/lib/src/exceptions/AlreadyResponded.dart +++ /dev/null @@ -1,11 +0,0 @@ -part of nyxx_interactions; - -/// Thrown when you have already responded to an interaction -class AlreadyRespondedError implements Error { - /// Returns a string representation of this object. - @override - String toString() => "AlreadyRespondedError: Interaction has already been acknowledged, you can now only send channel messages (with/without source)"; - - @override - StackTrace? get stackTrace => StackTrace.empty; -} diff --git a/nyxx_interactions/lib/src/exceptions/InteractionExpired.dart b/nyxx_interactions/lib/src/exceptions/InteractionExpired.dart deleted file mode 100644 index 0d34a9cdb..000000000 --- a/nyxx_interactions/lib/src/exceptions/InteractionExpired.dart +++ /dev/null @@ -1,21 +0,0 @@ -part of nyxx_interactions; - -/// Thrown when 15 minutes has passed since an interaction was called. -class InteractionExpiredError implements Error { - late final String _timeFrameString; - - InteractionExpiredError._15mins() { - this._timeFrameString = "15mins"; - } - - InteractionExpiredError._3secs() { - this._timeFrameString = "3secs"; - } - - /// Returns a string representation of this object. - @override - String toString() => "InteractionExpiredError: Interaction tokens are only valid for $_timeFrameString. It has been over $_timeFrameString and the token is now invalid."; - - @override - StackTrace? get stackTrace => StackTrace.empty; -} diff --git a/nyxx_interactions/lib/src/exceptions/ResponseRequired.dart b/nyxx_interactions/lib/src/exceptions/ResponseRequired.dart deleted file mode 100644 index 43cad6b26..000000000 --- a/nyxx_interactions/lib/src/exceptions/ResponseRequired.dart +++ /dev/null @@ -1,11 +0,0 @@ -part of nyxx_interactions; - -/// Thrown when you haven't sent a response yet -class ResponseRequiredError implements Error { - /// Returns a string representation of this object. - @override - String toString() => "ResponseRequiredError: Interaction needs an initial response before followups can be sent."; - - @override - StackTrace? get stackTrace => StackTrace.empty; -} diff --git a/nyxx_interactions/lib/src/internal/InteractionEndpoints.dart b/nyxx_interactions/lib/src/internal/InteractionEndpoints.dart deleted file mode 100644 index 97c2bc976..000000000 --- a/nyxx_interactions/lib/src/internal/InteractionEndpoints.dart +++ /dev/null @@ -1,423 +0,0 @@ -part of nyxx_interactions; - -abstract class IInteractionsEndpoints { - /// Sends followup for interaction with given [token]. Message will be created with [builder] - Future sendFollowup(String token, Snowflake applicationId, MessageBuilder builder); - - /// Fetches followup messagge from API - Future fetchFollowup(String token, Snowflake applicationId, Snowflake messageId); - - /// Acknowledges interaction that response can be sent within next 15 mins. - /// Response will be ephemeral if [hidden] is set to true. To response to different interaction types - /// (slash command, button...) [opCode] is used. - Future acknowledge(String token, String interactionId, bool hidden, int opCode); - - /// Response to interaction by editing original response. Used when interaction was acked before. - Future respondEditOriginal(String token, Snowflake applicationId, MessageBuilder builder, bool hidden); - - /// Response to interaction by creating response. Used when interaction wasn't acked before. - Future respondCreateResponse(String token, String interactionId, MessageBuilder builder, bool hidden, int respondOpCode); - - /// Fetch original interaction response. - Future fetchOriginalResponse(String token, Snowflake applicationId, String interactionId); - - /// Edits original interaction response using [builder] - Future editOriginalResponse(String token, Snowflake applicationId, MessageBuilder builder); - - /// Deletes original interaction response - Future deleteOriginalResponse(String token, Snowflake applicationId, String interactionId); - - /// Deletes followup message with given id - Future deleteFollowup(String token, Snowflake applicationId, Snowflake messageId); - - /// Edits followup message with given [messageId] - Future editFollowup(String token, Snowflake applicationId, Snowflake messageId, MessageBuilder builder); - - /// Fetches global commands of application - Stream fetchGlobalCommands(Snowflake applicationId); - - /// Fetches global command with given [commandId] - Future fetchGlobalCommand(Snowflake applicationId, Snowflake commandId); - - /// Edits global command with given [commandId] using [builder] - Future editGlobalCommand(Snowflake applicationId, Snowflake commandId, SlashCommandBuilder builder); - - /// Deletes global command with given [commandId] - Future deleteGlobalCommand(Snowflake applicationId, Snowflake commandId); - - /// Bulk overrides global commands. To delete all apps global commands pass empty list to [builders] - Stream bulkOverrideGlobalCommands(Snowflake applicationId, Iterable builders); - - /// Fetches all commands for given [guildId] - Stream fetchGuildCommands(Snowflake applicationId, Snowflake guildId); - - /// Fetches single guild command with given [commandId] - Future fetchGuildCommand(Snowflake applicationId, Snowflake commandId, Snowflake guildId); - - /// Edits single guild command with given [commandId] - Future editGuildCommand(Snowflake applicationId, Snowflake commandId, Snowflake guildId, SlashCommandBuilder builder); - - /// Deletes guild command with given commandId] - Future deleteGuildCommand(Snowflake applicationId, Snowflake commandId, Snowflake guildId); - - /// Bulk overrides global commands. To delete all apps global commands pass empty list to [builders] - Stream bulkOverrideGuildCommands(Snowflake applicationId, Snowflake guildId, Iterable builders); - - /// Overrides permissions for guild commands - Future bulkOverrideGuildCommandsPermissions(Snowflake applicationId, Snowflake guildId, Iterable builders); - - /// Responds to autocomplete interaction - Future respondToAutocomplete(Snowflake interactionId, String token, List builders); -} - -class _InteractionsEndpoints implements IInteractionsEndpoints { - final Nyxx _client; - - _InteractionsEndpoints(this._client); - - @override - Future acknowledge(String token, String interactionId, bool hidden, int opCode) async { - final url = "/interactions/$interactionId/$token/callback"; - final response = await this._client.httpEndpoints.sendRawRequest(url, "POST", body: { - "type": opCode, - "data": { - if (hidden) "flags": 1 << 6, - } - }); - - if (response is HttpResponseError) { - return Future.error(response); - } - } - - @override - Future deleteFollowup(String token, Snowflake applicationId, Snowflake messageId) => - this._client.httpEndpoints.sendRawRequest( - "webhooks/$applicationId/$token/messages/$messageId", - "DELETE" - ); - - @override - Future deleteOriginalResponse(String token, Snowflake applicationId, String interactionId) async { - final url = "/webhooks/$applicationId/$token/messages/@original"; - const method = "DELETE"; - - final response = await this._client.httpEndpoints.sendRawRequest(url, method); - if (response is HttpResponseError) { - return Future.error(response); - } - } - - @override - Future editFollowup(String token, Snowflake applicationId, Snowflake messageId, MessageBuilder builder) async { - final url = "/webhooks/$applicationId/$token/messages/$messageId"; - final body = BuilderUtility.buildWithClient(builder, _client); - - final response = await this._client.httpEndpoints.sendRawRequest(url, "PATCH", body: body); - if (response is HttpResponseError) { - return Future.error(response); - } - - return EntityUtility.createMessage(this._client, (response as HttpResponseSuccess).jsonBody as RawApiMap); - } - - @override - Future editOriginalResponse(String token, Snowflake applicationId, MessageBuilder builder) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/webhooks/$applicationId/$token/messages/@original", - "PATCH", - body: builder.build(this._client) - ); - - if (response is HttpResponseError) { - return Future.error(response); - } - - return EntityUtility.createMessage(this._client, (response as HttpResponseSuccess).jsonBody as RawApiMap); - } - - @override - Future fetchOriginalResponse(String token, Snowflake applicationId, String interactionId) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/webhooks/$applicationId/$token/messages/@original", - "GET" - ); - - if (response is HttpResponseError) { - return Future.error(response); - } - - return EntityUtility.createMessage(this._client, (response as HttpResponseSuccess).jsonBody as RawApiMap); - } - - @override - Future respondEditOriginal(String token, Snowflake applicationId, MessageBuilder builder, bool hidden) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/webhooks/$applicationId/$token/messages/@original", - "PATCH", - body: { - if (hidden) "flags": 1 << 6, - ...BuilderUtility.buildWithClient(builder, _client) - }, - files: builder.files ?? [] - ); - - if (response is HttpResponseError) { - return Future.error(response); - } - } - - @override - Future respondCreateResponse(String token, String interactionId, MessageBuilder builder, bool hidden, int respondOpCode) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/interactions/${interactionId.toString()}/$token/callback", - "POST", - body: { - "type": respondOpCode, - "data": { - if (hidden) "flags": 1 << 6, - ...BuilderUtility.buildWithClient(builder, _client) - }, - }, - files: builder.files ?? [] - ); - - if (response is HttpResponseError) { - return Future.error(response); - } - } - - @override - Future sendFollowup(String token, Snowflake applicationId, MessageBuilder builder) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/webhooks/$applicationId/$token", - "POST", - body: BuilderUtility.buildWithClient(builder, _client), - files: builder.files ?? [] - ); - - if (response is HttpResponseError) { - return Future.error(response); - } - - return EntityUtility.createMessage(this._client, (response as HttpResponseSuccess).jsonBody as RawApiMap); - } - - @override - Stream bulkOverrideGlobalCommands(Snowflake applicationId, Iterable builders) async* { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/commands", - "PUT", - body: [ - for(final builder in builders) - builder.build() - ] - ); - - if (response is HttpResponseError) { - yield* Stream.error(response); - } - - for (final rawRes in (response as HttpResponseSuccess).jsonBody as List) { - yield SlashCommand._new(rawRes as RawApiMap, this._client); - } - } - - @override - Stream bulkOverrideGuildCommands(Snowflake applicationId, Snowflake guildId, Iterable builders) async* { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/${this._client.app.id}/guilds/$guildId/commands", - "PUT", - body: [ - for(final builder in builders) - builder.build() - ] - ); - - if (response is HttpResponseError) { - yield* Stream.error(response); - } - - for (final rawRes in (response as HttpResponseSuccess).jsonBody as List) { - yield SlashCommand._new(rawRes as RawApiMap, this._client); - } - } - - @override - Future deleteGlobalCommand(Snowflake applicationId, Snowflake commandId) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/commands/$commandId", - "DELETE" - ); - - if (response is HttpResponseSuccess) { - return Future.error(response); - } - } - - @override - Future deleteGuildCommand(Snowflake applicationId, Snowflake commandId, Snowflake guildId) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/guilds/$guildId/commands/$commandId", - "DELETE" - ); - - if (response is HttpResponseSuccess) { - return Future.error(response); - } - } - - @override - Future editGlobalCommand(Snowflake applicationId, Snowflake commandId, SlashCommandBuilder builder) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/commands/$commandId", - "PATCH", - body: builder.build() - ); - - if (response is HttpResponseSuccess) { - return Future.error(response); - } - - return SlashCommand._new((response as HttpResponseSuccess).jsonBody as RawApiMap, _client); - } - - @override - Future editGuildCommand(Snowflake applicationId, Snowflake commandId, Snowflake guildId, SlashCommandBuilder builder) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/guilds/$guildId/commands/$commandId", - "GET", - body: builder.build() - ); - - if (response is HttpResponseSuccess) { - return Future.error(response); - } - - return SlashCommand._new((response as HttpResponseSuccess).jsonBody as RawApiMap, _client); - } - - @override - Future fetchGlobalCommand(Snowflake applicationId, Snowflake commandId) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/commands/$commandId", - "GET" - ); - - if (response is HttpResponseSuccess) { - return Future.error(response); - } - - return SlashCommand._new((response as HttpResponseSuccess).jsonBody as RawApiMap, _client); - } - - @override - Stream fetchGlobalCommands(Snowflake applicationId) async* { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/commands", - "GET" - ); - - if (response is HttpResponseError) { - yield* Stream.error(response); - } - - for (final commandSlash in (response as HttpResponseSuccess).jsonBody as List) { - yield SlashCommand._new(commandSlash as RawApiMap, _client); - } - } - - @override - Future fetchGuildCommand(Snowflake applicationId, Snowflake commandId, Snowflake guildId) async { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/guilds/$guildId/commands/$commandId", - "GET" - ); - - if (response is HttpResponseSuccess) { - return Future.error(response); - } - - return SlashCommand._new((response as HttpResponseSuccess).jsonBody as RawApiMap, _client); - } - - @override - Stream fetchGuildCommands(Snowflake applicationId, Snowflake guildId) async* { - final response = await this._client.httpEndpoints.sendRawRequest( - "/applications/$applicationId/guilds/$guildId/commands", - "GET" - ); - - if (response is HttpResponseError) { - yield* Stream.error(response); - } - - for (final commandSlash in (response as HttpResponseSuccess).jsonBody as List) { - yield SlashCommand._new(commandSlash as RawApiMap, _client); - } - } - - @override - Future bulkOverrideGlobalCommandsPermissions(Snowflake applicationId, Iterable builders) async { - final globalBody = builders - .where((builder) => builder.permissions != null && builder.permissions!.isNotEmpty) - .map((builder) => { - "id": builder._id.toString(), - "permissions": [for (final permsBuilder in builder.permissions!) permsBuilder.build()] - }) - .toList(); - - await this._client.httpEndpoints - .sendRawRequest("/applications/$applicationId/commands/permissions", "PUT", body: globalBody); - } - - @override - Future bulkOverrideGuildCommandsPermissions(Snowflake applicationId, Snowflake guildId, Iterable builders) async { - final guildBody = builders - .where((b) => b.permissions != null && b.permissions!.isNotEmpty) - .map((builder) => { - "id": builder._id.toString(), - "permissions": [for (final permsBuilder in builder.permissions!) permsBuilder.build()] - }) - .toList(); - - await this._client.httpEndpoints - .sendRawRequest("/applications/$applicationId/guilds/$guildId/commands/permissions", "PUT", body: guildBody); - - } - - @override - Future fetchFollowup(String token, Snowflake applicationId, Snowflake messageId) async { - final result = await this._client.httpEndpoints.sendRawRequest( - "/webhooks/$applicationId/$token/messages/${messageId.toString()}", - "GET" - ); - - if (result is HttpResponseError) { - return Future.error(result); - } - - return EntityUtility.createMessage(_client, (result as HttpResponseSuccess).jsonBody as RawApiMap); - } - - @override - Future respondToAutocomplete(Snowflake interactionId, String token, List builders) async { - final result = await this._client.httpEndpoints.sendRawRequest( - "/interactions/${interactionId.toString()}/$token/callback", - "POST", - body: { - "type": 8, - "data": { - "choices": [ - for (final builder in builders) - builder.build() - ] - } - } - ); - - if (result is HttpResponseError) { - return Future.error(result); - } - } -} diff --git a/nyxx_interactions/lib/src/internal/_EventController.dart b/nyxx_interactions/lib/src/internal/_EventController.dart deleted file mode 100644 index 0b6c2b11d..000000000 --- a/nyxx_interactions/lib/src/internal/_EventController.dart +++ /dev/null @@ -1,41 +0,0 @@ -part of nyxx_interactions; - -class _EventController implements Disposable { - /// Emitted when a a slash command is sent. - late final StreamController onSlashCommand; - - /// Emitted when a a slash command is sent. - late final StreamController onSlashCommandCreated; - - /// Emitted when button event is sent - late final StreamController onButtonEvent; - - /// Emitted when dropdown event is sent - late final StreamController onMultiselectEvent; - - /// Emitted when autocomplete interaction event is sent - late final StreamController onAutocompleteEvent; - - _EventController(Interactions _client) { - this.onSlashCommand = StreamController.broadcast(); - _client.onSlashCommand = this.onSlashCommand.stream; - - this.onSlashCommandCreated = StreamController.broadcast(); - _client.onSlashCommandCreated = this.onSlashCommandCreated.stream; - - this.onButtonEvent = StreamController.broadcast(); - _client.onButtonEvent = this.onButtonEvent.stream; - - this.onMultiselectEvent = StreamController.broadcast(); - _client.onMultiselectEvent = this.onMultiselectEvent.stream; - - this.onAutocompleteEvent = StreamController.broadcast(); - _client.onAutocompleteEvent = this.onAutocompleteEvent.stream; - } - - @override - Future dispose() async { - await this.onSlashCommand.close(); - await this.onSlashCommandCreated.close(); - } -} diff --git a/nyxx_interactions/lib/src/internal/sync/ICommandsSync.dart b/nyxx_interactions/lib/src/internal/sync/ICommandsSync.dart deleted file mode 100644 index 7947ca59e..000000000 --- a/nyxx_interactions/lib/src/internal/sync/ICommandsSync.dart +++ /dev/null @@ -1,7 +0,0 @@ -part of nyxx_interactions; - -/// Used to make multiple methods of checking if the slash commands have been edited since last update -abstract class ICommandsSync { - /// Should the commands & perms be synced? - FutureOr shouldSync(Iterable commands); -} diff --git a/nyxx_interactions/lib/src/internal/sync/LockFileCommandSync.dart b/nyxx_interactions/lib/src/internal/sync/LockFileCommandSync.dart deleted file mode 100644 index aee4ffa1e..000000000 --- a/nyxx_interactions/lib/src/internal/sync/LockFileCommandSync.dart +++ /dev/null @@ -1,121 +0,0 @@ -part of nyxx_interactions; - -/// Manually define command syncing rules -class LockFileCommandSync implements ICommandsSync { - const LockFileCommandSync(); - - @override - FutureOr shouldSync(Iterable commands) async { - final lockFile = File("./nyxx_interactions.lock"); - final lockFileMapData = {}; - - for (final c in commands) { - lockFileMapData[c.name] = new _LockfileCommand( - c.name, - c.description, - c.guild, - c.defaultPermissions, - c.permissions?.map((p) => new _LockfilePermission(p._type, p.id, p.hasPermission)) ?? [], - c.options.map((o) => new _LockfileOption(o.type.value, o.name, o.description, o.options ?? [])), - ).generateHash(); - } - - if (!lockFile.existsSync()) { - await lockFile.writeAsString(jsonEncode(lockFileMapData)); - return true; - } - - final lockfileData = jsonDecode(lockFile.readAsStringSync()) as _LockfileCommand; - - if (lockFileMapData == lockfileData) { - return false; - } - - await lockFile.writeAsString(jsonEncode(lockFileMapData)); - return true; - } -} - -class _LockfileCommand { - final String name; - final Snowflake? guild; - final bool defaultPermissions; - final Iterable<_LockfilePermission> permissions; - final String? description; - final Iterable<_LockfileOption> options; - - _LockfileCommand(this.name, this.description, this.guild, this.defaultPermissions, this.permissions, this.options); - - String generateHash() => md5.convert(utf8.encode(jsonEncode(this))).toString(); - - @override - bool operator ==(Object other) { - if (other is! _LockfileCommand) { - return false; - } - - if (other.defaultPermissions != this.defaultPermissions || - other.name != this.name || - other.guild != this.guild || - other.defaultPermissions != this.defaultPermissions) { - return false; - } - - return true; - } -} - -class _LockfileOption { - final int type; - final String name; - final String? description; - - late final Iterable<_LockfileOption> options; - - _LockfileOption(this.type, this.name, this.description, Iterable options) { - this.options = options.map( - (o) => new _LockfileOption( - o.type.value, - o.name, - o.description, - o.options ?? [], - ), - ); - } - - @override - bool operator ==(Object other) { - if (other is! _LockfileOption) { - return false; - } - - if (other.type != this.type || other.name != this.name || other.description != this.description) { - return false; - } - - return true; - } -} - -class _LockfilePermission { - final int permissionType; - final Snowflake? permissionEntityId; - final bool permissionsGranted; - - const _LockfilePermission(this.permissionType, this.permissionEntityId, this.permissionsGranted); - - @override - bool operator ==(Object other) { - if (other is! _LockfilePermission) { - return false; - } - - if (other.permissionType != this.permissionType || - other.permissionEntityId != this.permissionEntityId || - other.permissionsGranted != this.permissionsGranted) { - return false; - } - - return true; - } -} diff --git a/nyxx_interactions/lib/src/internal/sync/ManualCommandSync.dart b/nyxx_interactions/lib/src/internal/sync/ManualCommandSync.dart deleted file mode 100644 index b29252bc7..000000000 --- a/nyxx_interactions/lib/src/internal/sync/ManualCommandSync.dart +++ /dev/null @@ -1,13 +0,0 @@ -part of nyxx_interactions; - -/// Manually define command syncing rules -class ManualCommandSync implements ICommandsSync { - /// If commands & permissions should be overridden on next run. - final bool sync; - - /// Manually define command syncing rules - const ManualCommandSync({this.sync = true}); - - @override - FutureOr shouldSync(Iterable commands) => this.sync; -} diff --git a/nyxx_interactions/lib/src/internal/utils.dart b/nyxx_interactions/lib/src/internal/utils.dart deleted file mode 100644 index 05d950dae..000000000 --- a/nyxx_interactions/lib/src/internal/utils.dart +++ /dev/null @@ -1,71 +0,0 @@ -part of nyxx_interactions; - -/// Slash command names and subcommands names have to match this regex -final RegExp slashCommandNameRegex = RegExp(r"^[\w-]{1,32}$"); - -Iterable> _partition(Iterable list, bool Function(T) predicate) { - final matches = []; - final nonMatches = []; - - for(final e in list) { - if(predicate(e)) { - matches.add(e); - continue; - } - - nonMatches.add(e); - } - - return [matches, nonMatches]; -} - -/// Determine what handler should be executed based on [interaction] -String _determineInteractionCommandHandler(SlashCommandInteraction interaction) { - final commandHash = "${interaction.commandId}|${interaction.name}"; - - try { - final subCommandGroup = interaction.options.firstWhere((element) => element.type == CommandOptionType.subCommandGroup); - final subCommand = subCommandGroup.options.firstWhere((element) => element.type == CommandOptionType.subCommand); - - return "$commandHash|${subCommandGroup.name}|${subCommand.name}"; - // ignore: empty_catches - } on StateError { } - - try { - final subCommand = interaction.options.firstWhere((element) => element.type == CommandOptionType.subCommand); - return "$commandHash|${subCommand.name}"; - // ignore: empty_catches - } on StateError { } - - return commandHash; -} - -/// Groups [SlashCommandBuilder] for registering them later in bulk -Map> _groupSlashCommandBuilders(Iterable commands) { - final commandsMap = >{}; - - for(final slashCommand in commands) { - final id = slashCommand.guild!; - - if (commandsMap.containsKey(id)) { - commandsMap[id]!.add(slashCommand); - continue; - } - - commandsMap[id] = [slashCommand]; - } - - return commandsMap; -} - -Iterable _extractArgs(Iterable args) { - if (args.length == 1 - && (args.first.type == CommandOptionType.subCommand - || args.first.type == CommandOptionType.subCommandGroup - ) - ) { - return _extractArgs(args.first.options); - } - - return args; -} diff --git a/nyxx_interactions/lib/src/models/ArgChoice.dart b/nyxx_interactions/lib/src/models/ArgChoice.dart deleted file mode 100644 index a9d54db3f..000000000 --- a/nyxx_interactions/lib/src/models/ArgChoice.dart +++ /dev/null @@ -1,15 +0,0 @@ -part of nyxx_interactions; - -/// Choice that user can pick from. For [CommandOptionType.integer] or [CommandOptionType.string] -class ArgChoice { - /// Name of choice - late final String name; - - /// Value of choice - late final dynamic value; - - ArgChoice._new(RawApiMap raw) { - this.name = raw["name"] as String; - this.value = raw["value"]; - } -} diff --git a/nyxx_interactions/lib/src/models/CommandOption.dart b/nyxx_interactions/lib/src/models/CommandOption.dart deleted file mode 100644 index 6822bbb05..000000000 --- a/nyxx_interactions/lib/src/models/CommandOption.dart +++ /dev/null @@ -1,74 +0,0 @@ -part of nyxx_interactions; - -/// The type that a user should input for a [CommandOptionBuilder] -class CommandOptionType extends IEnum { - /// Specify an arg as a sub command - static const subCommand = const CommandOptionType(1); - /// Specify an arg as a sub command group - static const subCommandGroup = const CommandOptionType(2); - /// Specify an arg as a string - static const string = const CommandOptionType(3); - /// Specify an arg as an int - static const integer = const CommandOptionType(4); - /// Specify an arg as a bool - static const boolean = const CommandOptionType(5); - /// Specify an arg as a user e.g @HarryET#2954 - static const user = const CommandOptionType(6); - /// Specify an arg as a channel e.g. #Help - static const channel = const CommandOptionType(7); - /// Specify an arg as a role e.g. @RoleName - static const role = const CommandOptionType(8); - - /// Create new instance of CommandArgType - const CommandOptionType(int value) : super(value); -} - -/// An argument for a [SlashCommand]. -class CommandOption { - /// The type of arg that will be later changed to an INT value, their values can be seen in the table below: - /// | Name | Value | - /// |-------------------|-------| - /// | SUB_COMMAND | 1 | - /// | SUB_COMMAND_GROUP | 2 | - /// | STRING | 3 | - /// | INTEGER | 4 | - /// | BOOLEAN | 5 | - /// | USER | 6 | - /// | CHANNEL | 7 | - /// | ROLE | 8 | - late final CommandOptionType type; - - /// The name of your argument / sub-group. - late final String name; - - /// The description of your argument / sub-group. - late final String description; - - /// If this argument is required - late final bool required; - - /// Choices for [CommandOptionType.string] and [CommandOptionType.string] types for the user to pick from - late final List choices; - - /// If the option is a subcommand or subcommand group type, this nested options will be the parameters - late final List options; - - CommandOption._new(RawApiMap raw) { - this.type = CommandOptionType(raw["type"] as int); - this.name = raw["name"] as String; - this.description = raw["description"] as String; - this.required = raw["required"] as bool? ?? false; - - this.choices = [ - if (raw["choices"] != null) - for(final choiceRaw in raw["choices"]) - ArgChoice._new(choiceRaw as RawApiMap) - ]; - - this.options = [ - if (raw["options"] != null) - for(final optionRaw in raw["options"]) - CommandOption._new(optionRaw as RawApiMap) - ]; - } -} diff --git a/nyxx_interactions/lib/src/models/Interaction.dart b/nyxx_interactions/lib/src/models/Interaction.dart deleted file mode 100644 index d5faba4b8..000000000 --- a/nyxx_interactions/lib/src/models/Interaction.dart +++ /dev/null @@ -1,135 +0,0 @@ -part of nyxx_interactions; - -/// The Interaction data. e.g channel, guild and member -class Interaction extends SnowflakeEntity { - /// Reference to bot instance. - final Nyxx _client; - - /// The type of the interaction received. - late final int type; - - /// The guild the command was sent in. - late final Cacheable? guild; - - /// The channel the command was sent in. - late final Cacheable channel; - - /// The member who sent the interaction - late final Member? memberAuthor; - - /// Permission of member who sent the interaction. Will be set if [memberAuthor] - /// is not null - late final Permissions? memberAuthorPermissions; - - /// The user who sent the interaction. - late final User? userAuthor; - - /// Token to send requests - late final String token; - - /// Version of interactions api - late final int version; - - Interaction._new(this._client, RawApiMap raw) : super(Snowflake(raw["id"])) { - this.type = raw["type"] as int; - - if (raw["guild_id"] != null) { - this.guild = CacheUtility.createCacheableGuild(_client, Snowflake(raw["guild_id"]),); - } else { - this.guild = null; - } - - this.channel = CacheUtility.createCacheableTextChannel(_client, Snowflake(raw["channel_id"]),); - - if (raw["member"] != null) { - this.memberAuthor = EntityUtility.createGuildMember(_client, Snowflake(raw["guild_id"]), raw["member"] as RawApiMap); - this.memberAuthorPermissions = Permissions.fromInt(int.parse(raw["member"]["permissions"] as String)); - } else { - this.memberAuthor = null; - this.memberAuthorPermissions = null; - } - - if (raw["user"] != null) { - this.userAuthor = EntityUtility.createUser(_client, raw["user"] as RawApiMap); - } else if (raw["member"]["user"] != null) { - this.userAuthor = EntityUtility.createUser(_client, raw["member"]["user"] as RawApiMap); - } else { - this.userAuthor = null; - } - - this.token = raw["token"] as String; - this.version = raw["version"] as int; - } -} - -/// Interaction for slash command -class SlashCommandInteraction extends Interaction { - /// Name of interaction - late final String name; - - /// Args of the interaction - late final Iterable options; - - /// Id of command - late final Snowflake commandId; - - /// Additional data for command - late final InteractionDataResolved? resolved; - - SlashCommandInteraction._new(Nyxx client, RawApiMap raw) : super._new(client, raw) { - this.name = raw["data"]["name"] as String; - this.options = [ - if (raw["data"]["options"] != null) - for (final option in raw["data"]["options"] as List) - InteractionOption._new(option as RawApiMap) - ]; - this.commandId = Snowflake(raw["data"]["id"]); - - this.resolved = raw["data"]["resolved"] != null - ? InteractionDataResolved._new(raw["data"]["resolved"] as RawApiMap, this.guild?.id, client) - : null; - } - - /// Allows to fetch argument value by argument name - dynamic getArg(String name) { - try { - return this.options.firstWhere((element) => element.name == name).value; - } on Error { - return null; - } - } -} - -/// Interaction for button, dropdown, etc. -abstract class ComponentInteraction extends Interaction { - /// Custom id of component interaction - late final String customId; - - /// The message that the button was pressed on. - late final Message? message; - - ComponentInteraction._new(Nyxx client, RawApiMap raw): super._new(client, raw) { - this.customId = raw["data"]["custom_id"] as String; - - // Discord doesn't include guild's id in the message object even if its a guild message but is included in the data so its been added to the object so that guild message can be used if the interaction is from a guild. - this.message = EntityUtility.createMessage(_client, { - ...raw["message"], - if (guild != null) "guild_id": guild!.id.toString() - }); - } -} - -/// Interaction invoked when button is pressed -class ButtonInteraction extends ComponentInteraction { - ButtonInteraction._new(Nyxx client, Map raw): super._new(client, raw); -} - -/// Interaction when multi select is triggered -class MultiselectInteraction extends ComponentInteraction { - /// Values selected by the user - late final List values; - - MultiselectInteraction._new(Nyxx client, Map raw): super._new(client, raw) { - this.values = (raw["data"]["values"] as List).cast(); - } -} diff --git a/nyxx_interactions/lib/src/models/InteractionDataResolved.dart b/nyxx_interactions/lib/src/models/InteractionDataResolved.dart deleted file mode 100644 index 24bd2e558..000000000 --- a/nyxx_interactions/lib/src/models/InteractionDataResolved.dart +++ /dev/null @@ -1,65 +0,0 @@ -part of nyxx_interactions; - -/// Partial channel object for interactions -class PartialChannel extends SnowflakeEntity { - /// Channel name - late final String name; - - /// Type of channel - late final ChannelType type; - - /// Permissions of user in channel - late final Permissions permissions; - - PartialChannel._new(RawApiMap raw): super(Snowflake(raw["id"])) { - this.name = raw["name"] as String; - this.type = ChannelType.from(raw["type"] as int); - this.permissions = Permissions.fromInt(int.parse(raw["permissions"].toString())); - } -} - -/// Additional data for slash command -class InteractionDataResolved { - /// Resolved [User]s - late final Iterable users; - - /// Resolved [Member]s - late final Iterable members; - - /// Resolved [Role]s - late final Iterable roles; - - /// Resolved [PartialChannel]s - late final Iterable channels; - - InteractionDataResolved._new(RawApiMap raw, Snowflake? guildId, Nyxx client) { - this.users = [ - if (raw["users"] != null) - for (final rawUserEntry in (raw["users"] as RawApiMap).entries) - EntityUtility.createUser(client, rawUserEntry.value as RawApiMap) - ]; - - this.members = [ - if (raw["members"] != null) - for (final rawMemberEntry in (raw["members"] as RawApiMap).entries) - EntityUtility.createGuildMember(client, guildId!, { - ...rawMemberEntry.value as RawApiMap, - "user": { - "id": rawMemberEntry.key - } - }) - ]; - - this.roles = [ - if (raw["roles"] != null) - for (final rawRoleEntry in (raw["roles"] as RawApiMap).entries) - EntityUtility.createRole(client, guildId!, rawRoleEntry.value as RawApiMap) - ]; - - this.channels = [ - if (raw["channels"] != null) - for (final rawChannelEntry in (raw["channels"] as RawApiMap).entries) - PartialChannel._new(rawChannelEntry.value as RawApiMap) - ]; - } -} diff --git a/nyxx_interactions/lib/src/models/InteractionOption.dart b/nyxx_interactions/lib/src/models/InteractionOption.dart deleted file mode 100644 index d4bd50d84..000000000 --- a/nyxx_interactions/lib/src/models/InteractionOption.dart +++ /dev/null @@ -1,33 +0,0 @@ -part of nyxx_interactions; - -/// The option given by the user when sending a command -class InteractionOption { - /// The value given by the user - late final dynamic value; - - /// Type of interaction - late final CommandOptionType type; - - /// Name of option - late final String name; - - /// Any args under this as you can have sub commands - late final Iterable options; - - /// True if options is focused - late final bool isFocused; - - InteractionOption._new(RawApiMap raw) { - this.value = raw["value"] as dynamic; - this.name = raw["name"] as String; - this.type = CommandOptionType(raw["type"] as int); - - if (raw["options"] != null) { - this.options = (raw["options"] as List).map((e) => InteractionOption._new(e as RawApiMap)); - } else { - this.options = []; - } - - this.isFocused = raw["focused"] as bool? ?? false; - } -} diff --git a/nyxx_interactions/lib/src/models/SlashCommand.dart b/nyxx_interactions/lib/src/models/SlashCommand.dart deleted file mode 100644 index 6e2221b44..000000000 --- a/nyxx_interactions/lib/src/models/SlashCommand.dart +++ /dev/null @@ -1,42 +0,0 @@ -part of nyxx_interactions; - -/// Represents slash command that is returned from Discord API. -class SlashCommand extends SnowflakeEntity { - /// Unique id of the parent application - late final Snowflake applicationId; - - /// Command name to be shown to the user in the Slash Command UI - late final String name; - - /// Command description shown to the user in the Slash Command UI - late final String description; - - /// The arguments that the command takes - late final List options; - - /// The type of command - late final SlashCommandType type; - - /// Guild id of the command, if not global - late final Cacheable? guild; - - /// Whether the command is enabled by default when the app is added to a guild - late final bool defaultPermissions; - - SlashCommand._new(RawApiMap raw, Nyxx client): super(Snowflake(raw["id"])) { - this.applicationId = Snowflake(raw["application_id"]); - this.name = raw["name"] as String; - this.description = raw["description"] as String; - this.type = SlashCommandType(raw["type"] as int? ?? 1); - this.guild = raw["guild_id"] != null - ? CacheUtility.createCacheableGuild(client, Snowflake(raw["guild_id"])) - : null; - this.defaultPermissions = raw["default_permission"] as bool? ?? true; - - this.options = [ - if (raw["options"] != null) - for(final optionRaw in raw["options"]) - CommandOption._new(optionRaw as RawApiMap) - ]; - } -} diff --git a/nyxx_interactions/lib/src/models/SlashCommandType.dart b/nyxx_interactions/lib/src/models/SlashCommandType.dart deleted file mode 100644 index 101c169b2..000000000 --- a/nyxx_interactions/lib/src/models/SlashCommandType.dart +++ /dev/null @@ -1,17 +0,0 @@ -part of nyxx_interactions; - -/// Type of the slash command. Since context menus reuses slash commands -/// backed, slash commands cna have different types based on context. -class SlashCommandType extends IEnum { - /// Normal slash command, invoked from chat - static const SlashCommandType chat = const SlashCommandType(1); - - /// Context menu when right clicking on user - static const SlashCommandType user = const SlashCommandType(2); - - /// Context menu when right clicking on message - static const SlashCommandType message = const SlashCommandType(3); - - /// Creates instance of [SlashCommandType] from [value] - const SlashCommandType(int value) : super(value); -} diff --git a/nyxx_interactions/pubspec.yaml b/nyxx_interactions/pubspec.yaml deleted file mode 100644 index f440a3fdb..000000000 --- a/nyxx_interactions/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: nyxx_interactions -version: 2.0.2 -description: Nyxx Interactions Module. Discord library for Dart. Simple, robust framework for creating discord bots for Dart language. -homepage: https://github.com/nyxx-discord/nyxx -repository: https://github.com/nyxx-discord/nyxx -documentation: https://nyxx.l7ssha.xyz -issue_tracker: https://github.com/nyxx-discord/nyxx/issues - -environment: - sdk: '>=2.13.0 <3.0.0' - -dependencies: - crypto: "^3.0.1" - logging: "^1.0.1" - nyxx: "^2.0.0" - -dev_dependencies: - test: "^1.17.0" diff --git a/nyxx_interactions/test/unit.dart b/nyxx_interactions/test/unit.dart deleted file mode 100644 index ef22d8900..000000000 --- a/nyxx_interactions/test/unit.dart +++ /dev/null @@ -1,23 +0,0 @@ -import "package:nyxx/nyxx.dart"; -import "package:nyxx_interactions/interactions.dart"; - -import "package:test/test.dart"; - -final client = NyxxRest("dum", 0); -final slashCommandNameRegexMatcher = matches(slashCommandNameRegex); - -void main() { - group("test utils", () { - test("test slash command regex", () { - expect("test", slashCommandNameRegexMatcher); - expect("Atest", slashCommandNameRegexMatcher); - expect("test-test", slashCommandNameRegexMatcher); - - expect("test.test", isNot(slashCommandNameRegexMatcher)); - expect(".test", isNot(slashCommandNameRegexMatcher)); - expect("*test", isNot(slashCommandNameRegexMatcher)); - expect("/test", isNot(slashCommandNameRegexMatcher)); - expect("\\test", isNot(slashCommandNameRegexMatcher)); - }); - }); -} diff --git a/nyxx_lavalink/.gitignore b/nyxx_lavalink/.gitignore deleted file mode 100644 index 65c34dc86..000000000 --- a/nyxx_lavalink/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -# Files and directories created by pub. -.dart_tool/ -.packages - -# Conventional directory for build outputs. -build/ - -# Omit committing pubspec.lock for library packages; see -# https://dart.dev/guides/libraries/private-files#pubspeclock. -pubspec.lock diff --git a/nyxx_lavalink/CHANGELOG.md b/nyxx_lavalink/CHANGELOG.md deleted file mode 100644 index 56ef1ce7d..000000000 --- a/nyxx_lavalink/CHANGELOG.md +++ /dev/null @@ -1,18 +0,0 @@ -## 2.0.1 -_15.10.2021_ - -- Move to Apache 2 license - -## 2.0.0 -_03.10.2021_ - -> Bumped version to 2.0 for compatibility with nyxx - -- Initial implementation (covers 100% of lavalink API) - -## 2.0.0-rc.1 - -- Added `TrackStuck` and `TrackException` events. -- Removed `type` property from `TrackEndEvent` -- Changed `position` property from `PlayerUpdateStateEvent` type to `int?` to avoid deserializing errors when using Andesite instead of Lavalink -- Updated `Exception` model diff --git a/nyxx_lavalink/LICENSE b/nyxx_lavalink/LICENSE deleted file mode 100644 index a94f9d161..000000000 --- a/nyxx_lavalink/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2021 AlvaroMS25, Szymon Uglis and contributors - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/nyxx_lavalink/README.md b/nyxx_lavalink/README.md deleted file mode 100644 index 5c7828ce3..000000000 --- a/nyxx_lavalink/README.md +++ /dev/null @@ -1,139 +0,0 @@ -# nyxx_lavalink - -[![pub](https://img.shields.io/pub/v/nyxx.svg)](https://pub.dartlang.org/packages/nyxx) -[![documentation](https://img.shields.io/badge/Documentation-nyxx-yellow.svg)](https://www.dartdocs.org/documentation/nyxx/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.commander-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.commander/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.interactions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.interactions/latest/) -[![documentation](https://img.shields.io/badge/Documentation-nyxx.extentions-yellow.svg)](https://www.dartdocs.org/documentation/nyxx.extensions/latest/) - -Simple, robust framework for creating discord bots for Dart language. - -
- -### Features - -- **Slash commands support**
- Supports and provides easy API for creating and handling slash commands -- **Commands framework included**
- A fast way to create a bot with command support. Implementing the framework is simple - and everything is done automatically. -- **Lavalink support**
- Nyxx allows you to create music bots by adding support to [Lavalink](https://github.com/freyacodes/Lavalink) API -- **Cross Platform**
- Nyxx works on the command line, in the browser, and on mobile devices. -- **Fine Control**
- Nyxx allows you to control every outgoing HTTP request or WebSocket message. -- **Complete**
- Nyxx supports nearly all Discord API endpoints. - - -## Quick example - -Basic usage: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - bot.onMessageReceived.listen((event) { - if (event.message.content == "!ping") { - event.message.channel.sendMessage(MessageBuilder.content("Pong!")); - } - }); -} -``` - -Slash commands: -```dart -void main() { - final bot = Nyxx("<%TOKEN%>", GatewayIntents.allUnprivileged); - Interactions(bot) - ..registerSlashCommand( - SlashCommandBuilder("hi", "This is example slash command", []) - ..registerHandler((event) async { - await event.acknowledge(); - - await event.respond(MessageBuilder.content("Hello World!")); - }) - ); -} -``` - -Commands: -```dart -void main() { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - - Commander(bot, prefix: "!!!") - ..registerCommand("ping", (context, message) => context.reply(MessageBuilder.content("Pong!"))); -} -``` - -Lavalink -```dart -void main() async { - final bot = Nyxx("TOKEN", GatewayIntents.allUnprivileged); - final guildId = Snowflake("GUILD_ID"); - final channelId = Snowflake("CHANNEL_ID"); - - final cluster = Cluster(bot, Snowflake("BOT_ID")); - - await cluster.addNode(NodeOptions()); - - bot.onMessageReceived.listen((event) async { - if (event.message.content == "!join") { - final channel = await bot.fetchChannel(channelId); - - cluster.getOrCreatePlayerNode(guildId); - - channel.connect(); - } else { - final node = cluster.getOrCreatePlayerNode(guildId); - - final searchResults = await node.searchTracks(event.message.content); - - node.play(guildId, searchResults.tracks[0]).queue(); - } - }); -} -``` - -## More examples - -Nyxx examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx/example). - -Commander examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx_commander/example) - -Slash commands (interactions) examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx_interactions/example) - -Lavalink examples can be found [here](https://github.com/l7ssha/nyxx/tree/dev/nyxx_lavalink/example) - -### Example bots -- [Running on Dart](https://github.com/l7ssha/running_on_dart) -- [Lavalink testbot](https://github.com/AlvaroMS25/nyxx_lavalink_testbot) - -## Documentation, help and examples - -**Dartdoc documentation is hosted on [pub](https://www.dartdocs.org/documentation/nyxx/latest/). -This wiki just fills gap in docs with more descriptive guides and tutorials.** - -#### [Discord API docs](https://discordapp.com/developers/docs/intro) -Discord API documentation features rich descriptions about all topics that nyxx covers. - -#### [Discord API Guild](https://discord.gg/discord-api) -The unofficial guild for Discord Bot developers. To get help with nyxx check `#dart_nyxx` channel. - -#### [Dartdocs](https://www.dartdocs.org/documentation/nyxx/latest/) -The dartdocs page will always have the documentation for the latest release. - -#### [Dev docs](https://nyxx.l7ssha.xyz) -You can read about upcoming changes in the library on my website. - -#### [Wiki](https://github.com/l7ssha/nyxx/wiki) -Wiki documentation are designed to match the latest Nyxx release. - -## Contributing to Nyxx - -Read [contributing document](https://github.com/l7ssha/nyxx/blob/development/CONTRIBUTING.md) - -## Credits - - * [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx). diff --git a/nyxx_lavalink/analysis_options.yaml b/nyxx_lavalink/analysis_options.yaml deleted file mode 100644 index 128725250..000000000 --- a/nyxx_lavalink/analysis_options.yaml +++ /dev/null @@ -1,106 +0,0 @@ -analyzer: - strong-mode: - implicit-casts: false -linter: - rules: - - avoid_empty_else - - comment_references - - control_flow_in_finally - - empty_statements - - hash_and_equals - - iterable_contains_unrelated_type - - list_remove_unrelated_type - - avoid_slow_async_io - - cancel_subscriptions - - test_types_in_equals - - throw_in_finally - - valid_regexps - - always_declare_return_types - - annotate_overrides - - avoid_init_to_null - - avoid_return_types_on_setters - - await_only_futures - - camel_case_types - - constant_identifier_names - - empty_constructor_bodies - - library_names - - library_prefixes - - non_constant_identifier_names - - only_throw_errors - - package_api_docs - - package_prefixed_library_names - - prefer_is_not_empty - - slash_for_doc_comments - - type_init_formals - - unnecessary_getters_setters - - package_names - - unnecessary_await_in_return - - use_function_type_syntax_for_parameters - - avoid_returning_null_for_future - - no_duplicate_case_values - - unnecessary_statements - - always_require_non_null_named_parameters - - always_put_required_named_parameters_first - - avoid_catches_without_on_clauses - - avoid_function_literals_in_foreach_calls - - avoid_redundant_argument_values - - avoid_returning_null - - avoid_returning_null_for_void - - avoid_returning_this - - camel_case_extensions - - curly_braces_in_flow_control_structures - - directives_ordering - - empty_catches - - join_return_with_assignment - - leading_newlines_in_multiline_strings - - missing_whitespace_between_adjacent_strings - - no_runtimeType_toString - - null_closures - - omit_local_variable_types - - one_member_abstracts - - prefer_adjacent_string_concatenation - - prefer_collection_literals - - prefer_conditional_assignment - - prefer_const_constructors - - prefer_const_constructors_in_immutables - - prefer_const_declarations - - prefer_const_literals_to_create_immutables - - prefer_constructors_over_static_methods - - prefer_contains - - prefer_double_quotes - - prefer_equal_for_default_values - - prefer_expression_function_bodies - - prefer_final_fields - - prefer_final_in_for_each - - prefer_final_locals - - prefer_for_elements_to_map_fromIterable - - prefer_foreach - - prefer_function_declarations_over_variables - - prefer_generic_function_type_aliases - - prefer_if_elements_to_conditional_expressions - - prefer_if_null_operators - - prefer_initializing_formals - - prefer_inlined_adds - - prefer_int_literals - - prefer_interpolation_to_compose_strings - - prefer_is_empty - - provide_deprecation_message - - prefer_typing_uninitialized_variables - - public_member_api_docs - - unawaited_futures - - unnecessary_brace_in_string_interps - - unnecessary_lambdas - - unnecessary_null_in_if_null_operators - - unnecessary_parenthesis - - unnecessary_raw_strings - - unnecessary_string_escapes - - use_rethrow_when_possible - - use_string_buffers - - void_checks - - use_to_and_as_if_applicable - - sort_pub_dependencies - - prefer_is_not_operator - - prefer_iterable_whereType - - prefer_mixin - - prefer_null_aware_operators - - prefer_spread_collections diff --git a/nyxx_lavalink/example/example.dart b/nyxx_lavalink/example/example.dart deleted file mode 100644 index 1a3e43afb..000000000 --- a/nyxx_lavalink/example/example.dart +++ /dev/null @@ -1,58 +0,0 @@ -import "dart:io"; - -import "package:nyxx_lavalink/lavalink.dart"; -import "package:nyxx/nyxx.dart"; - -void main() async { - final client = Nyxx(Platform.environment["DISCORD_TOKEN"]!, GatewayIntents.allUnprivileged); - final cluster = Cluster(client, Snowflake("YOUR_BOT_ID")); - - // This is a really simple example, so we'll define the guild and - // the channel where the bot will play music on - final guildId = Snowflake("GUILD_ID_HERE"); - final channelId = Snowflake("CHANNEL_ID_HERE"); - - // Add your lava link nodes. Empty constructor assumes default settings to lavalink. - await cluster.addNode(NodeOptions()); - - await for (final msg in client.onMessageReceived) { - if(msg.message.content == "!join") { - final channel = await client.fetchChannel(channelId); - - // Create lava link node for guild - cluster.getOrCreatePlayerNode(guildId); - - // Connect to channel - channel.connect(); - } else if(msg.message.content == "!queue") { - // Fetch node for guild - final node = cluster.getOrCreatePlayerNode(guildId); - - // get player for guild - final player = node.players[guildId]; - - print(player!.queue); - } else if (msg.message.content == "!skip") { - final node = cluster.getOrCreatePlayerNode(guildId); - - // skip the current track, if it's the last on the queue, the - // player will stop automatically - node.skip(guildId); - } else if(msg.message.content == "!nodes") { - print("${cluster.connectedNodes.length} available nodes"); - } else if (msg.message.content == "!update") { - final node = cluster.getOrCreatePlayerNode(guildId); - - node.updateOptions(NodeOptions()); - } else { - // Any other message will be processed as potential title to play lava link - final node = cluster.getOrCreatePlayerNode(guildId); - - // search for given query using lava link - final searchResults = await node.searchTracks(msg.message.content); - - // add found song to queue and play - node.play(guildId, searchResults.tracks[0]).queue(); - } - } -} diff --git a/nyxx_lavalink/lib/lavalink.dart b/nyxx_lavalink/lib/lavalink.dart deleted file mode 100644 index 92b0023e4..000000000 --- a/nyxx_lavalink/lib/lavalink.dart +++ /dev/null @@ -1,34 +0,0 @@ -library nyxx_lavalink; - -import "dart:async"; -import "dart:collection"; -import "dart:convert"; -import "dart:io"; -import "dart:isolate"; - -import "package:http/http.dart" show Client; -import "package:logging/logging.dart"; -import "package:nyxx/nyxx.dart" show Nyxx, Snowflake, VoiceStateUpdateEvent, VoiceServerUpdateEvent, Disposable, IEnum; - -part "src/_EventDispatcher.dart"; -part "src/Cluster.dart"; -part "src/ClusterException.dart"; -part "src/HttpException.dart"; - -part "src/model/BaseEvent.dart"; -part "src/model/Exception.dart"; -part "src/model/GuildPlayer.dart"; -part "src/model/PlayerUpdate.dart"; -part "src/model/PlayParameters.dart"; -part "src/model/Stats.dart"; -part "src/model/Track.dart"; -part "src/model/TrackEnd.dart"; -part "src/model/TrackException.dart"; -part "src/model/TrackStart.dart"; -part "src/model/TrackStuck.dart"; -part "src/model/WebSocketClosed.dart"; -part "src/model/SearchPlatform.dart"; - -part "src/node/Node.dart"; -part "src/node/nodeRunner.dart"; -part "src/node/Options.dart"; diff --git a/nyxx_lavalink/lib/src/Cluster.dart b/nyxx_lavalink/lib/src/Cluster.dart deleted file mode 100644 index 07a3d8244..000000000 --- a/nyxx_lavalink/lib/src/Cluster.dart +++ /dev/null @@ -1,254 +0,0 @@ -part of nyxx_lavalink; - -/// Cluster of lavalink nodes -class Cluster { - /// A reference to the client - final Nyxx _client; - - /// The client id provided to lavalink; - final Snowflake _clientId; - - /// All available nodes, ordered by node id - final Map _nodes = {}; - - /// Returns a map with the nodes connected to lavalink cluster - UnmodifiableMapView get connectedNodes => UnmodifiableMapView(this._nodes); - - /// Nodes that are currently connecting to server, when a node gets connected - /// it will be moved to [_nodes], and when reconnecting will be moved here again - final Map _connectingNodes = {}; - - /// Returns a map with the nodes that are actually disconnected from lavalink - UnmodifiableMapView get disconnectedNodes => UnmodifiableMapView(this._connectingNodes); - - /// A map to keep the assigned node id for each player - final Map _nodeLocations = {}; - - /// The last id assigned to a node, this is used to avoid repeating ids - /// since if we use a repeated id, the existing node would be overwritten and lost - int _lastId = 0; - - final _receivePort = ReceivePort(); - late final Stream _receiveStream; - - final _logger = Logger("Lavalink"); - - /// Emitted when stats are sent from lavalink - late final Stream onStatsReceived; - /// Emitted when a player gets updated - late final Stream onPlayerUpdate; - /// Emitted when a track starts playing - late final Stream onTrackStart; - /// Emitted when a track ends playing - late final Stream onTrackEnd; - /// Emitted when a track gets an exception during playback - late final Stream onTrackException; - /// Emitted when a track gets stuck - late final Stream onTrackStuck; - /// Emitted when a web socket is closed - late final Stream onWebSocketClosed; - - late final _EventDispatcher _eventDispatcher; - - Future _addNode(NodeOptions nodeOptions, int nodeId) async { - await Isolate.spawn(_handleNode, this._receivePort.sendPort); - - final isolateSendPort = await this._receiveStream.firstWhere((element) => element is SendPort) as SendPort; - - nodeOptions.clientId = this._clientId; - nodeOptions.nodeId = nodeId; - - isolateSendPort.send(nodeOptions._toJson()); - - // Say the node to start the connection - isolateSendPort.send({"cmd": "CONNECT"}); - - final node = Node._fromOptions(this, nodeOptions, isolateSendPort); - - this._connectingNodes[nodeId] = node; - } - - void _handleNodeMessage(dynamic message) { - if (message is SendPort) { - return; - } - - final map = message as Map; - - this._logger.finer("Receved data from node ${map["nodeId"]}, data: $map"); - - switch(map["cmd"]) { - case "DISPATCH": - this._eventDispatcher.dispatchEvent(map); - break; - - case "LOG": { - Level? level; - - switch (map["level"]) { - case "INFO": - level = Level.INFO; - break; - - case "WARNING": - level = Level.WARNING; - break; - } - - _logger.log(level!, map["message"]); - } - break; - - case "EXITED": { - final nodeId = map["nodeId"]! as int; - this._nodes.remove(nodeId); - this._connectingNodes.remove(nodeId); - - _logger.info("[Node $nodeId] Exited"); - } - break; - - case "CONNECTED": { - final node = this._connectingNodes.remove(map["nodeId"] as int); - - if (node != null) { - this._nodes[node.options.nodeId] = node; - - _logger.info("[Node ${map["nodeId"]}] Connected to lavalink"); - } - } - break; - - case "DISCONNECTED": { - final node = this._nodes.remove(map["nodeId"] as int); - - if (node == null) { - return; - } - this._connectingNodes[node.options.nodeId] = node; - - // this makes possible for a player to be moved to another node - node._players.forEach((guildId, _) => this._nodeLocations.remove(guildId)); - - // Also delete the players, so them can be created again on another node - node._players.clear(); - - _logger.info("[Node ${map["nodeId"]}] Disconnected from lavalink"); - } - break; - } - } - - void _registerEvents() { - this._client.onVoiceServerUpdate.listen((event) async { - final node = this._nodes[this._nodeLocations[event.guild.id]]; - if (node == null) { - return; - } - - final player = node._players[event.guild.id]; - if (player == null) { - return; - } - - player._handleServerUpdate(event); - }); - - this._client.onVoiceStateUpdate.listen((event) async { - if (event.raw["d"]["user_id"] != _clientId.toString()) { - return; - } - if (event.state.guild == null) { - return; - } - - final node = this._nodes[this._nodeLocations[event.state.guild!.id]]; - if (node == null) { - return; - } - - final player = node._players[event.state.guild!.id]; - if (player == null) { - return; - } - - player._handleStateUpdate(event); - }); - } - - /// Get the best available node, it is recommended to use [getOrCreatePlayerNode] instead - /// as this won't create the player itself if it doesn't exists - Node get bestNode { - if (this._nodes.isEmpty) { - throw ClusterException._new("No available nodes"); - } - if (this._nodes.length == 1) { - return this._nodes.values.first; - } - - /// Node id of the node who has fewer players - int? minNodeId; - /// Number of players the node has - int? minNodePlayers; - - this._nodes.forEach((id, node) { - if (minNodeId == null && minNodePlayers == null) { - minNodeId = id; - minNodePlayers = node._players.length; - } else { - if (node._players.length < minNodePlayers!) { - minNodeId = id; - minNodePlayers = node._players.length; - } - } - }); - - return this._nodes[minNodeId]!; - } - - /// Attempts to get the node containing a player for a specific guild id - /// - /// if the player doesn't exist, then the best node is retrieved and the player created - Node getOrCreatePlayerNode(Snowflake guildId) { - final nodePreview = this._nodeLocations.containsKey(guildId) - ? this._nodes[_nodeLocations[guildId]] - : this.bestNode; - - final node = nodePreview ?? this.bestNode; - - if (!node._players.containsKey(guildId)) { - node.createPlayer(guildId); - } - - return node; - } - - /// Attempts to retrieve a node disconnected from lavalink by its id, - /// this method does not work with nodes that have exceeded the maximum - /// reconnect attempts as those get removed from cluster - Node? getDisconnectedNode(int nodeId) => this._connectingNodes[nodeId]; - - /// Adds and initializes a node - Future addNode(NodeOptions options) async { - - /// Set a tiny delay so we can ensure we don't repeat ids - await Future.delayed(const Duration(milliseconds: 50)); - - this._lastId += 1; - - await this._addNode(options, this._lastId); - } - - /// Creates a new cluster ready to start adding connections - Cluster(this._client, this._clientId, [Level? loggingLevel]) { - this._registerEvents(); - - this._eventDispatcher = _EventDispatcher(this); - - this._receiveStream = this._receivePort.asBroadcastStream(); - - this._receiveStream.listen(_handleNodeMessage); - - Logger.root.level = loggingLevel ?? Level.INFO; - } -} diff --git a/nyxx_lavalink/lib/src/ClusterException.dart b/nyxx_lavalink/lib/src/ClusterException.dart deleted file mode 100644 index 20ed705f2..000000000 --- a/nyxx_lavalink/lib/src/ClusterException.dart +++ /dev/null @@ -1,12 +0,0 @@ -part of nyxx_lavalink; - -/// An exception related to cluster functions -class ClusterException implements Exception { - /// The actual error description - final String error; - - ClusterException._new(this.error); - - @override - String toString() => "Lavalink cluster error: $error"; -} diff --git a/nyxx_lavalink/lib/src/HttpException.dart b/nyxx_lavalink/lib/src/HttpException.dart deleted file mode 100644 index b886266f9..000000000 --- a/nyxx_lavalink/lib/src/HttpException.dart +++ /dev/null @@ -1,13 +0,0 @@ -part of nyxx_lavalink; - -/// An exception that can be thrown when using -/// [Node.searchTracks] or [Node.autoSearch] if the request fails -class HttpException implements Exception { - /// The status code of the request - final int code; - - HttpException._new(this.code); - - @override - String toString() => "Lavalink server responded with $code code"; -} diff --git a/nyxx_lavalink/lib/src/_EventDispatcher.dart b/nyxx_lavalink/lib/src/_EventDispatcher.dart deleted file mode 100644 index 477743188..000000000 --- a/nyxx_lavalink/lib/src/_EventDispatcher.dart +++ /dev/null @@ -1,109 +0,0 @@ -part of nyxx_lavalink; - -class _EventDispatcher implements Disposable { - final Cluster cluster; - - final StreamController onStatsReceived = StreamController.broadcast(); - final StreamController onPlayerUpdate = StreamController.broadcast(); - final StreamController onTrackStart = StreamController.broadcast(); - final StreamController onTrackEnd = StreamController.broadcast(); - final StreamController onTrackException = StreamController.broadcast(); - final StreamController onTrackStuck = StreamController.broadcast(); - final StreamController onWebSocketClosed = StreamController.broadcast(); - - _EventDispatcher(this.cluster) { - cluster.onStatsReceived = this.onStatsReceived.stream; - cluster.onPlayerUpdate = this.onPlayerUpdate.stream; - cluster.onTrackStart = this.onTrackStart.stream; - cluster.onTrackEnd = this.onTrackEnd.stream; - cluster.onTrackException = this.onTrackException.stream; - cluster.onTrackStuck = this.onTrackStuck.stream; - cluster.onWebSocketClosed = this.onWebSocketClosed.stream; - } - - void dispatchEvent(Map json) { - final node = cluster._nodes[json["nodeId"]]; - - if(node == null) { - return; - } - - cluster._logger.fine("[Node ${json["nodeId"]}] Dispatching ${json["event"]}"); - - switch(json["event"]) { - case "TrackStartEvent": - this.onTrackStart.add( - TrackStartEvent._fromJson(cluster._client, node, - json["data"] as Map - ) - ); - break; - - case "TrackEndEvent": { - final trackEnd = TrackEndEvent._fromJson(cluster._client, node, - json["data"] as Map - ); - - this.onTrackEnd.add( - trackEnd - ); - - node._handleTrackEnd(trackEnd); - } - break; - - case "TrackExceptionEvent": - this.onTrackException.add( - TrackExceptionEvent._fromJson(cluster._client, node, - json["data"] as Map - ) - ); - break; - - case "TrackStuckEvent": - this.onTrackStuck.add( - TrackStuckEvent._fromJson(cluster._client, node, - json["data"] as Map - ) - ); - break; - - case "WebSocketClosedEvent": - this.onWebSocketClosed.add( - WebSocketClosedEvent._fromJson(cluster._client, node, - json["data"] as Map - ) - ); - break; - - case "stats": { - final stats = StatsEvent._fromJson(cluster._client, node, - json["data"] as Map - ); - - // Put the stats into the node - node._stats = stats; - - this.onStatsReceived.add(stats); - } - break; - - case "playerUpdate": - this.onPlayerUpdate.add( - PlayerUpdateEvent._fromJson(cluster._client, node, - json["data"] as Map - ) - ); - break; - } - } - - @override - Future dispose() async { - await this.onStatsReceived.close(); - await this.onPlayerUpdate.close(); - await this.onTrackStart.close(); - await this.onTrackEnd.close(); - await this.onWebSocketClosed.close(); - } -} diff --git a/nyxx_lavalink/lib/src/model/BaseEvent.dart b/nyxx_lavalink/lib/src/model/BaseEvent.dart deleted file mode 100644 index 3e9360fc1..000000000 --- a/nyxx_lavalink/lib/src/model/BaseEvent.dart +++ /dev/null @@ -1,13 +0,0 @@ -part of nyxx_lavalink; - -/// Base event class which all events must inherit -class BaseEvent { - /// A reference to the current client - final Nyxx client; - - /// A reference to the node this event belongs to - final Node node; - - /// Creates a new base event instance - BaseEvent(this.client, this.node); -} diff --git a/nyxx_lavalink/lib/src/model/Exception.dart b/nyxx_lavalink/lib/src/model/Exception.dart deleted file mode 100644 index 1efd8e039..000000000 --- a/nyxx_lavalink/lib/src/model/Exception.dart +++ /dev/null @@ -1,23 +0,0 @@ -part of nyxx_lavalink; - -/// A exception object that can be sent by lavalink at certain endpoints -class LavalinkException { - /// Exception message - late final String? message; - /// The error message - late final String? error; - /// The cause of the exception - late final String? cause; - /// Exception severity - late final String? severity; - - LavalinkException._fromJson(Map json) { - if (json.containsKey("exception")) { - this.message = json["exception"]["message"] as String?; - this.severity = json["exception"]["severity"] as String?; - this.cause = json["exception"]["cause"] as String?; - } else { - this.error = json["error"] as String?; - } - } -} diff --git a/nyxx_lavalink/lib/src/model/GuildPlayer.dart b/nyxx_lavalink/lib/src/model/GuildPlayer.dart deleted file mode 100644 index 643cf8da1..000000000 --- a/nyxx_lavalink/lib/src/model/GuildPlayer.dart +++ /dev/null @@ -1,40 +0,0 @@ -part of nyxx_lavalink; - -/// A player of a specific guild -class GuildPlayer { - /// Track queue - List queue = []; - /// The currently playing track - QueuedTrack? nowPlaying; - /// Guild where this player operates on - final Snowflake guildId; - - /// A map to combine server state and server update events to send them to lavalink - final Map _serverUpdate = {}; - /// A reference to the parent node - final Node _nodeRef; - - GuildPlayer._new(this._nodeRef, this.guildId); - - void _dispatchVoiceUpdate() { - if(_serverUpdate.containsKey("sessionId") && _serverUpdate.containsKey("event")) { - _nodeRef._sendPayload("voiceUpdate", this.guildId, _serverUpdate); - } - } - - void _handleServerUpdate(VoiceServerUpdateEvent event) { - this._serverUpdate["event"] = { - "token": event.token, - "endpoint": event.endpoint, - "guildId": this.guildId.toString() - }; - - _dispatchVoiceUpdate(); - } - - void _handleStateUpdate(VoiceStateUpdateEvent event) { - this._serverUpdate["sessionId"] = event.state.sessionId; - - _dispatchVoiceUpdate(); - } -} diff --git a/nyxx_lavalink/lib/src/model/PlayParameters.dart b/nyxx_lavalink/lib/src/model/PlayParameters.dart deleted file mode 100644 index 71e247564..000000000 --- a/nyxx_lavalink/lib/src/model/PlayParameters.dart +++ /dev/null @@ -1,74 +0,0 @@ -part of nyxx_lavalink; - -/// Parameters to start playing a track -class PlayParameters { - final Node _node; - /// The track to play - final Track track; - /// The guild where the track will be played - final Snowflake guildId; - /// Wether to replace the track or not - bool replace; - /// The time at where the track will start to play - Duration startTime; - /// The time at where the track will stop playing - Duration? endTime; - - /// The requester of the track - Snowflake? requester; - - /// The channel where this track was requested - Snowflake? channelId; - - /// Create a new play parameters object, it is recommended to create this - /// through [Node.play] - PlayParameters( - this._node, - this.track, - this.guildId, - this.replace, - this.startTime, - this.endTime, - this.requester, - this.channelId - ); - - /// Forces the song to start playing - void startPlaying() { - if (this.endTime == null) { - _node._sendPayload("play", this.guildId, { - "track": track.track, - "noReplace": !this.replace, - "startTime": this.startTime.inMilliseconds - }); - - return; - } - - _node._sendPayload("play", this.guildId, { - "track": track.track, - "noReplace": !this.replace, - "startTime": this.startTime, - "endTime": this.endTime!.inMilliseconds - }); - } - - /// Puts the track on the queue and starts playing if necessary - void queue() { - final player = _node._players[this.guildId]; - - if (player == null) { - return; - } - - final queuedTrack = QueuedTrack._new(this.track, this.startTime, this.endTime, this.requester, this.channelId); - - // Whether if the node should start playing the track - final shouldPlay = player.nowPlaying == null && player.queue.isEmpty; - player.queue.add(queuedTrack); - - if (shouldPlay) { - this._node._playNext(this.guildId); - } - } -} diff --git a/nyxx_lavalink/lib/src/model/PlayerUpdate.dart b/nyxx_lavalink/lib/src/model/PlayerUpdate.dart deleted file mode 100644 index 12d147a9a..000000000 --- a/nyxx_lavalink/lib/src/model/PlayerUpdate.dart +++ /dev/null @@ -1,25 +0,0 @@ -part of nyxx_lavalink; - -/// Player update event dispatched by lavalink at player progression -class PlayerUpdateEvent extends BaseEvent { - /// State of the current player - late final PlayerUpdateStateEvent state; - - /// Guild id where player comes from - late final Snowflake guildId; - - PlayerUpdateEvent._fromJson(Nyxx client, Node node, Map json) : super(client, node) { - guildId = Snowflake(json["guildId"]); - this.state = PlayerUpdateStateEvent._new(json["state"]["time"] as int, json["state"]["position"] as int?); - } -} - -/// The state of a player at a given moment -class PlayerUpdateStateEvent { - /// The timestamp of the player - final int time; - /// The position where the current track is now on - final int? position; - - PlayerUpdateStateEvent._new(this.time, this.position); -} diff --git a/nyxx_lavalink/lib/src/model/SearchPlatform.dart b/nyxx_lavalink/lib/src/model/SearchPlatform.dart deleted file mode 100644 index 915ae6262..000000000 --- a/nyxx_lavalink/lib/src/model/SearchPlatform.dart +++ /dev/null @@ -1,15 +0,0 @@ -part of nyxx_lavalink; - -/// Search platforms supported by Lavalink -class SearchPlatform extends IEnum { - /// Youtube - static const youtube = SearchPlatform._create("ytsearch"); - - /// Youtube Music - static const youtubeMusic = SearchPlatform._create("ytmsearch"); - - /// SoundCloud - static const soundcloud = SearchPlatform._create("scsearch"); - - const SearchPlatform._create(String value) : super(value); -} diff --git a/nyxx_lavalink/lib/src/model/Stats.dart b/nyxx_lavalink/lib/src/model/Stats.dart deleted file mode 100644 index 06f7778bb..000000000 --- a/nyxx_lavalink/lib/src/model/Stats.dart +++ /dev/null @@ -1,77 +0,0 @@ -part of nyxx_lavalink; - -/// Stats update event dispatched by lavalink -class StatsEvent extends BaseEvent { - /// Number of playing players - late final int playingPlayers; - ///Memory usage stats - late final MemoryStats memory; - /// Frame sending stats - late final FrameStats? frameStats; - /// Total amount of players - late final int players; - /// Cpu usage stats - late final CpuStats cpu; - /// Server uptime - late final int uptime; - - StatsEvent._fromJson(Nyxx client, Node node, Map json) : super(client, node) { - this.playingPlayers = json["playingPlayers"] as int; - this.players = json["players"] as int; - this.uptime = json["uptime"] as int; - this.memory = MemoryStats._fromJson(json["memory"] as Map); - this.frameStats = json["frameStats"] == null ? null : FrameStats._fromJson(json["frameStats"] as Map); - this.cpu = CpuStats._fromJson(json["cpu"] as Map); - } -} - -/// Stats about frame sending to discord -class FrameStats { - /// Sent frames - late final int sent; - /// Deficit frames - late final int deficit; - /// Nulled frames - late final int nulled; - - FrameStats._fromJson(Map json) { - this.sent = json["sent"] as int; - this.deficit = json["deficit"] as int; - this.nulled = json["nulled"] as int; - } -} - -/// Cpu usage stats -class CpuStats { - /// Amount of available cores on the cpu - late final int cores; - /// The total load of the machine where lavalink is running on - late final num systemLoad; - /// The total load of lavalink server - late final num lavalinkLoad; - - CpuStats._fromJson(Map json) { - this.cores = json["cores"] as int; - this.systemLoad = json["systemLoad"] as num; - this.lavalinkLoad = json["lavalinkLoad"] as num; - } -} - -/// Memory usage stats -class MemoryStats { - /// Reservable memory - late final int reservable; - /// Used memory - late final int used; - /// Free/unused memory - late final int free; - /// Total allocated memory - late final int allocated; - - MemoryStats._fromJson(Map json) { - this.reservable = json["reservable"] as int; - this.used = json["used"] as int; - this.free = json["free"] as int; - this.allocated = json["allocated"] as int; - } -} diff --git a/nyxx_lavalink/lib/src/model/Track.dart b/nyxx_lavalink/lib/src/model/Track.dart deleted file mode 100644 index 3adce7158..000000000 --- a/nyxx_lavalink/lib/src/model/Track.dart +++ /dev/null @@ -1,102 +0,0 @@ -part of nyxx_lavalink; - -/// Represents a track already on a player queue -class QueuedTrack { - /// The actual track - final Track track; - /// Where should start lavalink playing the track - final Duration startTime; - /// If the track should stop playing before finish and where - final Duration? endTime; - - /// The requester of the track - final Snowflake? requester; - - /// The channel where this track was requested - final Snowflake? channelId; - - /// Create a new QueuedTrack instance - QueuedTrack._new(this.track, this.startTime, this.endTime, this.requester, this.channelId); -} - -/// Lavalink track object -class Track { - /// Base64 encoded track - late final String track; - /// Optional information about the track - late final TrackInfo? info; - - /// Create a new track instance - Track(this.track, this.info); - - Track._fromJson(Map json) { - if (json.containsKey("info")) { - this.info = TrackInfo._fromJson(json["info"] as Map); - } - - this.track = json["track"] as String; - } -} - -/// Track details -class TrackInfo { - /// Track identifier - late final String identifier; - /// If the track is seekable (if it's a streaming it's not) - late final bool seekable; - /// The author of the track - late final String author; - /// The length of the track - late final int length; - /// Whether the track is a streaming or not - late final bool stream; - /// Position returned by lavalink - late final int position; - /// The title of the track - late final String title; - /// Url of the track - late final String uri; - - TrackInfo._fromJson(Map json) { - this.identifier = json["identifier"] as String; - this.seekable = json["isSeekable"] as bool; - this.author = json["author"] as String; - this.length = json["length"] as int; - this.stream = json["isStream"] as bool; - this.position = json["position"] as int; - this.title = json["title"] as String; - this.uri = json["uri"] as String; - } -} - -/// Playlist info -class PlaylistInfo { - /// Name of the playlist - late final String? name; - /// Currently selected track - late final int? selectedTrack; - - PlaylistInfo._fromJson(Map json) { - this.name = json["name"] as String?; - this.selectedTrack = json["selectedTrack"] as int?; - } -} - -/// Object returned from lavalink when searching -class Tracks { - /// Information about loaded playlist - late final PlaylistInfo playlistInfo; - /// Load type (track, playlist, etc) - late final String loadType; - /// Loaded tracks - late final List tracks; - /// Occurred exception (if occurred) - late final LavalinkException? exception; - - Tracks._fromJson(Map json) { - this.playlistInfo = PlaylistInfo._fromJson(json["playlistInfo"] as Map); - this.loadType = json["loadType"] as String; - this.tracks = (json["tracks"] as List).map((t) => Track._fromJson(t as Map)).toList(); - this.exception = json["exception"] == null ? null : LavalinkException._fromJson(json["exception"] as Map); - } -} diff --git a/nyxx_lavalink/lib/src/model/TrackEnd.dart b/nyxx_lavalink/lib/src/model/TrackEnd.dart deleted file mode 100644 index 592165060..000000000 --- a/nyxx_lavalink/lib/src/model/TrackEnd.dart +++ /dev/null @@ -1,17 +0,0 @@ -part of nyxx_lavalink; - -/// Object sent when a track ends playing -class TrackEndEvent extends BaseEvent { - /// Reason to the track to end - late final String reason; - /// Base64 encoded track - late final String track; - /// Guild where the track ended - late final Snowflake guildId; - - TrackEndEvent._fromJson(Nyxx client, Node node, Map json) : super(client, node) { - this.reason = json["reason"] as String; - this.track = json["track"] as String; - this.guildId = Snowflake(json["guildId"] as String); - } -} diff --git a/nyxx_lavalink/lib/src/model/TrackException.dart b/nyxx_lavalink/lib/src/model/TrackException.dart deleted file mode 100644 index 7b2babe1f..000000000 --- a/nyxx_lavalink/lib/src/model/TrackException.dart +++ /dev/null @@ -1,17 +0,0 @@ -part of nyxx_lavalink; - -/// Object sent when a track gets an exception while playing -class TrackExceptionEvent extends BaseEvent { - /// Base64 encoded track - late final String track; - /// The occurred error - late final LavalinkException exception; - /// Guild id where the track got an exception - late final Snowflake guildId; - - TrackExceptionEvent._fromJson(Nyxx client, Node node, Map json) : super(client, node) { - this.track = json["track"] as String; - this.exception = LavalinkException._fromJson(json); - this.guildId = Snowflake(json["guildId"]); - } -} diff --git a/nyxx_lavalink/lib/src/model/TrackStart.dart b/nyxx_lavalink/lib/src/model/TrackStart.dart deleted file mode 100644 index 2db924b65..000000000 --- a/nyxx_lavalink/lib/src/model/TrackStart.dart +++ /dev/null @@ -1,17 +0,0 @@ -part of nyxx_lavalink; - -/// Object sent when a track starts playing -class TrackStartEvent extends BaseEvent { - /// Track start type (if its replaced or not the track) - late final String startType; - /// Base64 encoded track - late final String track; - /// Guild where the track started - late final Snowflake guildId; - - TrackStartEvent._fromJson(Nyxx client, Node node, Map json) : super(client, node) { - this.startType = json["type"] as String; - this.track = json["track"] as String; - this.guildId = Snowflake(json["guildId"]); - } -} diff --git a/nyxx_lavalink/lib/src/model/TrackStuck.dart b/nyxx_lavalink/lib/src/model/TrackStuck.dart deleted file mode 100644 index d6959a883..000000000 --- a/nyxx_lavalink/lib/src/model/TrackStuck.dart +++ /dev/null @@ -1,17 +0,0 @@ -part of nyxx_lavalink; - -/// Object sent when a track gets stuck when playing -class TrackStuckEvent extends BaseEvent { - /// Base64 encoded track - late final String track; - /// The wait threshold that was exceeded for this event to trigger - late final int thresholdMs; - /// Guild where the track got stuck - late final Snowflake guildId; - - TrackStuckEvent._fromJson(Nyxx client, Node node, Map json) : super(client, node) { - this.track = json["track"] as String; - this.thresholdMs = json["thresholdMs"] as int; - this.guildId = Snowflake(json["guildId"] as String); - } -} diff --git a/nyxx_lavalink/lib/src/model/WebSocketClosed.dart b/nyxx_lavalink/lib/src/model/WebSocketClosed.dart deleted file mode 100644 index 69f68902b..000000000 --- a/nyxx_lavalink/lib/src/model/WebSocketClosed.dart +++ /dev/null @@ -1,20 +0,0 @@ -part of nyxx_lavalink; - -/// Web socket closed event from lavalink -class WebSocketClosedEvent extends BaseEvent { - /// Guild where the websocket has closed - late final Snowflake guildId; - /// Close code - late final int code; - /// Reason why the socket closed - late final String reason; - /// If the connection was closed by discord - late final bool byRemote; - - WebSocketClosedEvent._fromJson(Nyxx client, Node node, Map json) : super(client, node) { - this.guildId = Snowflake(json["guildId"]); - this.code = json["code"] as int; - this.reason = json["reason"] as String; - this.byRemote = json["byRemote"] as bool; - } -} diff --git a/nyxx_lavalink/lib/src/node/Node.dart b/nyxx_lavalink/lib/src/node/Node.dart deleted file mode 100644 index 212cc6e0b..000000000 --- a/nyxx_lavalink/lib/src/node/Node.dart +++ /dev/null @@ -1,269 +0,0 @@ -part of nyxx_lavalink; - -/// Represents an active and running lavalink node -class Node { - /// Node options, such as host, port, etc.. - NodeOptions options; - - /// A map with guild ids as keys and players as values - final Map _players = {}; - - /// Returns a map with all the players the node currently has - UnmodifiableMapView get players => UnmodifiableMapView(this._players); - - /// Last stats received by this node - StatsEvent? _stats; - - /// Returns the last stats received by this node - StatsEvent? get stats => this._stats; - - /// Http client used with this node - final Client _httpClient = Client(); - - final SendPort _nodeSendPort; - late String _httpUri; - late Map _defaultHeaders; - final Cluster _cluster; - /// A regular expression to avoid searching when a link is provided - final RegExp _urlRegex = RegExp(r"https?://(?:www\.)?.+"); - - /// Build a new Node - Node._fromOptions(this._cluster, this.options, this._nodeSendPort) { - this._httpUri = options.ssl - ? "https://${options.host}:${options.port}" - : "http://${options.host}:${options.port}"; - - this._defaultHeaders = { - "Authorization": options.password, - "Num-Shards": options.shards.toString(), - "User-Id": options.clientId.toString() - }; - } - - void _sendPayload(String op, Snowflake guildId, [Map? data]) async { - if (data == null) { - _nodeSendPort.send({"cmd": "SEND", "data": { - "op": op, - "guildId": guildId.toString(), - }}); - } else { - _nodeSendPort.send({"cmd": "SEND", "data": { - "op": op, - "guildId": guildId.toString(), - ...data - }}); - } - } - - void _playNext(Snowflake guildId) async { - final player = this._players[guildId]; - - if (player == null) { - return; - } - - final track = player.queue.first; - - player.nowPlaying = track; - - if (track.endTime == null) { - this._sendPayload("play", guildId, { - "track": track.track.track, - "noReplace": false, - "startTime": track.startTime.inMilliseconds, - }); - } else { - this._sendPayload("play", guildId, { - "track": track.track.track, - "noReplace": false, - "startTime": track.startTime.inMilliseconds, - "endTime": track.endTime!.inMilliseconds - }); - } - } - - void _handleTrackEnd(TrackEndEvent event) { - if(!(event.reason == "FINISHED")) { - return; - } - - final player = this._players[event.guildId]; - - if (player == null) { - return; - } - - player.queue.removeAt(0); - player.nowPlaying = null; - - if (player.queue.isEmpty) { - return; - } - - - _playNext(event.guildId); - } - - /// Destroys a player - void destroy(Snowflake guildId) { - _sendPayload("destroy", guildId); - - // delete the actual player - this._players.remove(guildId); - - // delete the relationship between this node and the player so - // if this guild creates a new player, it can be assigned to other node - this._cluster._nodeLocations.remove(guildId); - } - - /// Stops a player - void stop(Snowflake guildId) { - final player = this._players[guildId]; - - if (player == null) { - return; - } - - player.queue.clear(); - player.nowPlaying = null; - - _sendPayload("stop", guildId); - } - - /// Skips a track, starting the next one if available or stopping the player if not - void skip(Snowflake guildId) { - final player = this._players[guildId]; - - if (player == null) { - return; - } - - if (player.queue.isEmpty) { - return; - } else if (player.queue.length == 1) { - stop(guildId); - return; - } else { - player.queue.removeAt(0); - this._playNext(guildId); - } - } - - /// Set the pause state of a player - /// - /// this method is internally used by [resume] and [pause] - void setPause(Snowflake guildId, bool pauseState) { - _sendPayload("pause", guildId, {"pause": pauseState}); - } - - /// Seeks for a given time at the currently playing track - void seek(Snowflake guildId, Duration time) { - _sendPayload("seek", guildId, { - "position": time.inMilliseconds - }); - } - - /// Sets the volume for a guild player, [volume] should be a number between 1 to 1000 - void volume(Snowflake guildId, int volume) { - final trimmed = volume.clamp(0, 1000); - - _sendPayload("volume", guildId, { - "volume": trimmed - }); - } - - /// Pauses a guild player - void pause(Snowflake guildId) { - setPause(guildId, true); - } - - /// Resumes the track playback of a guild player - void resume(Snowflake guildId) { - setPause(guildId, false); - } - - /// Searches a given query over the lavalink api and returns the results - Future searchTracks(String query) async { - final response = await _httpClient.get(Uri.parse( - "${this._httpUri}/loadtracks?identifier=$query"), - headers: this._defaultHeaders - ); - - if (!(response.statusCode == 200)) { - throw HttpException._new(response.statusCode); - } - - return Tracks._fromJson(jsonDecode(response.body) as Map); - } - - /// Searches a provided query on selected platform (YouTube by default), - /// if the query is a link it's searched directly by the link - Future autoSearch( - String query, { - SearchPlatform platform = SearchPlatform.youtube, - }) async { - if (this._urlRegex.hasMatch(query)) { - return searchTracks(query); - } - - return searchTracks("${platform.value}:$query"); - } - - /// Get the [PlayParameters] object for a specific track - PlayParameters play(Snowflake guildId, Track track, { - bool replace = false, - Duration startTime = const Duration(), - Duration? endTime, - Snowflake? requester, - Snowflake? channelId - }) => PlayParameters( - this, - track, - guildId, - replace, - startTime, - endTime, - requester, - channelId - ); - - /// Shuts down the node - void shutdown() { - this._nodeSendPort.send({"cmd": "SHUTDOWN"}); - } - - /// Create a new player for a specific guild - GuildPlayer createPlayer(Snowflake guildId) { - final player = GuildPlayer._new(this, guildId); - - this._players[guildId] = player; - _cluster._nodeLocations[guildId] = this.options.nodeId; - - return player; - } - - /// Updates the [NodeOptions] property of the node, also reconnects the - /// websocket to the new options - void updateOptions(NodeOptions newOptions) { - // Set the node id and client id before sending it to the isolate - newOptions.clientId = this.options.clientId; - newOptions.nodeId = this.options.nodeId; - - _nodeSendPort.send({"cmd": "UPDATE", "data": newOptions._toJson()}); - - this.options = newOptions; - } - - /// Tells the node to disconnect from lavalink server - void disconnect() { - _nodeSendPort.send({"cmd": "DISCONNECT"}); - } - - /// Tells the node to reconnect to lavalink server - void reconnect() { - _nodeSendPort.send({"cmd": "RECONNECT"}); - } - - @override - String toString() => "Node ${this.options.nodeId}"; -} diff --git a/nyxx_lavalink/lib/src/node/Options.dart b/nyxx_lavalink/lib/src/node/Options.dart deleted file mode 100644 index 27e5c6eba..000000000 --- a/nyxx_lavalink/lib/src/node/Options.dart +++ /dev/null @@ -1,60 +0,0 @@ -part of nyxx_lavalink; - -/// Class containing all node options needed to establish and mantain a connection -/// with lavalink server -class NodeOptions { - /// Host where lavalink is running - late final String host; - /// Port used by lavalink rest & socket - late final int port; - /// Whether to use a tls connection or not - late final bool ssl; - /// Password to connect to the server - late final String password; - /// Shards the bot is operating on - late final int shards; - /// Max connect attempts before shutting down a node - late final int maxConnectAttempts; - /// How much time should the node wait before trying to reconnect - /// to lavalink server again - late final Duration delayBetweenReconnections; - /// Client id - late final Snowflake clientId; - /// Node id, you **must** not set this yourself - late final int nodeId; - - /// Constructor to build a new node builder - NodeOptions({ - this.host = "localhost", - this.port = 2333, - this.ssl = false, - this.password = "youshallnotpass", - this.shards = 1, - this.maxConnectAttempts = 5, - this.delayBetweenReconnections = const Duration(seconds: 5) - }); - - NodeOptions._fromJson(Map json) { - host = json["host"] as String; - port = json["port"] as int; - ssl = json["ssl"] as bool; - password = json["password"] as String; - shards = json["shards"] as int; - clientId = Snowflake(json["clientId"] as int); - nodeId = json["nodeId"] as int; - maxConnectAttempts = json["maxConnectAttempts"] as int; - delayBetweenReconnections = Duration(milliseconds: json["delayBetweenReconnections"] as int); - } - - Map _toJson() => { - "host": this.host, - "port": this.port, - "ssl": this.ssl, - "password": this.password, - "shards": this.shards, - "clientId": this.clientId.id, - "nodeId": this.nodeId, - "maxConnectAttempts": this.maxConnectAttempts, - "delayBetweenReconnections": this.delayBetweenReconnections.inMilliseconds - }; -} diff --git a/nyxx_lavalink/lib/src/node/nodeRunner.dart b/nyxx_lavalink/lib/src/node/nodeRunner.dart deleted file mode 100644 index 1bc687617..000000000 --- a/nyxx_lavalink/lib/src/node/nodeRunner.dart +++ /dev/null @@ -1,141 +0,0 @@ -part of nyxx_lavalink; - -/* - The actual node runner - Following nyxx design, the node communicates with the cluster using json - First message will always be the [NodeOptions] data - - Can receive: - * SEND - Sends a given json payload directly to the server through the web socket - * CONNECT - Starts the connection to lavalink server - * UPDATE - Updates the current node data - * RECONNECT - Reconnects to lavalink server - * DISCONNECT - Disconnects from lavalink server - * SHUTDOWN - Shuts down the node and kills the isolate - - Can send: - * DISPATCH - Dispatch the given event - * DISCONNECTED - WebSocket disconnected - * CONNECTED - WebSocket connected - * ERROR - An error occurred - * EXITED - Node shutdown itself - * LOG - Log something -*/ -Future _handleNode(SendPort clusterPort) async { - WebSocket? socket; - StreamSubscription? socketStream; - - // First thing to do is to return a send port to the cluster to communicate with the node - final receivePort = ReceivePort(); - final receiveStream = receivePort.asBroadcastStream(); - clusterPort.send(receivePort.sendPort); - - var node = NodeOptions._fromJson(await receiveStream.first as Map); - - void process(Map json) { - if (json["op"] == "event") { - clusterPort.send({"cmd": "DISPATCH", "nodeId": node.nodeId, "event": json["type"], "data": json}); - } else { - clusterPort.send({"cmd": "DISPATCH", "nodeId": node.nodeId, "event": json["op"], "data": json}); - } - } - - Future connect() async { - final address = node.ssl ? "wss://${node.host}:${node.port}" : "ws://${node.host}:${node.port}"; - var actualAttempt = 1; - - while (actualAttempt < node.maxConnectAttempts) { - try { - clusterPort.send({"cmd": "LOG", "nodeId": node.nodeId, "level": "INFO", "message": "[Node ${node.nodeId}] Trying to connect to lavalink ($actualAttempt/${node.maxConnectAttempts})"}); - - await WebSocket.connect(address, headers: { - "Authorization": node.password, - "Num-Shards": node.shards, - "User-Id": node.clientId.id - }).then((ws) { - clusterPort.send({"cmd": "CONNECTED", "nodeId": node.nodeId}); - - socket = ws; - - socketStream = socket!.listen((data) { - process(jsonDecode(data as String) as Map); - }, onDone: () async { - clusterPort.send({"cmd": "DISCONNECTED", "nodeId": node.nodeId}); - await connect(); - - return; - }, - cancelOnError: true, - onError: (err) { - clusterPort.send({"cmd": "ERROR", "nodeId": node.nodeId, "code": socket!.closeCode, "reason": socket!.closeReason}); - } - ); - - return; - }); - - return; - // ignore: avoid_catches_without_on_clauses - } catch (e) { - clusterPort.send({"cmd": "LOG", "nodeId": node.nodeId, "level": "WARNING", "message": "[Node ${node.nodeId}] Error while trying to connect to lavalink; $e"}); - } - - clusterPort.send({"cmd": "LOG", "nodeId": node.nodeId, "level": "WARNING", "message": "[Node ${node.nodeId}] Failed to connect to lavalink, retrying"}); - - actualAttempt += 1; - - await Future.delayed(node.delayBetweenReconnections); - } - - clusterPort.send({"cmd": "EXITED", "nodeId": node.nodeId}); - } - - Future disconnect() async { - await socket?.close(1000); - await socketStream?.cancel(); - - clusterPort.send({"cmd": "DISCONNECTED", "nodeId": node.nodeId}); - } - - Future reconnect() async { - await disconnect(); - await Future.delayed(const Duration(milliseconds: 300)); - await connect(); - } - - await for (final msg in receiveStream) { - switch (msg["cmd"]) { - case "SEND": - socket?.add(jsonEncode(msg["data"])); - break; - - case "CONNECT": - await connect(); - break; - - case "UPDATE": - node = NodeOptions._fromJson(msg["data"] as Map); - await reconnect(); - break; - - case "DISCONNECT": - await disconnect(); - break; - - case "RECONNECT": - await reconnect(); - break; - - case "SHUTDOWN": { - clusterPort.send({"cmd": "EXITED", "nodeId": node.nodeId}); - await disconnect(); - receivePort.close(); - Isolate.current.kill(priority: Isolate.immediate); - } - break; - - default: - break; - } - } -} diff --git a/nyxx_lavalink/pubspec.yaml b/nyxx_lavalink/pubspec.yaml deleted file mode 100644 index 1005fe881..000000000 --- a/nyxx_lavalink/pubspec.yaml +++ /dev/null @@ -1,18 +0,0 @@ -name: nyxx_lavalink -version: 2.0.1 -description: Nyxx Lavalink Module -homepage: https://github.com/nyxx-discord/nyxx -repository: https://github.com/nyxx-discord/nyxx -documentation: https://nyxx.l7ssha.xyz -issue_tracker: https://github.com/nyxx-discord/nyxx/issues - -environment: - sdk: '>=2.13.0 <3.0.0' - -dependencies: - http: "^0.13.3" - logging: "^1.0.1" - nyxx: "^2.0.0" - -dev_dependencies: - test: "^1.17.0" diff --git a/nyxx_lavalink/test/nyxx_lavalink_test.dart b/nyxx_lavalink/test/nyxx_lavalink_test.dart deleted file mode 100644 index e69de29bb..000000000 diff --git a/nyxx/pubspec.yaml b/pubspec.yaml similarity index 100% rename from nyxx/pubspec.yaml rename to pubspec.yaml diff --git a/nyxx/test/kitty.webp b/test/kitty.webp similarity index 100% rename from nyxx/test/kitty.webp rename to test/kitty.webp diff --git a/nyxx/test/travis.dart b/test/travis.dart similarity index 100% rename from nyxx/test/travis.dart rename to test/travis.dart diff --git a/nyxx/test/unit.dart b/test/unit.dart similarity index 100% rename from nyxx/test/unit.dart rename to test/unit.dart