Fixes for slash commands; Implemented Commander like interface for interactions
This commit is contained in:
parent
975d7b9473
commit
bcd12ee369
|
@ -1,7 +1,12 @@
|
||||||
part of nyxx_interactions;
|
part of nyxx_interactions;
|
||||||
|
|
||||||
|
typedef SlashCommandHandlder = FutureOr<void> Function(InteractionEvent);
|
||||||
|
|
||||||
/// Interaction extension for Nyxx. Allows use of: Slash Commands.
|
/// Interaction extension for Nyxx. Allows use of: Slash Commands.
|
||||||
class Interactions {
|
class Interactions {
|
||||||
|
static const _interactionCreateCommand = "INTERACTION_CREATE";
|
||||||
|
static const _op0 = 0;
|
||||||
|
|
||||||
late final Nyxx _client;
|
late final Nyxx _client;
|
||||||
final Logger _logger = Logger("Interactions");
|
final Logger _logger = Logger("Interactions");
|
||||||
final List<SlashCommand> _commands = [];
|
final List<SlashCommand> _commands = [];
|
||||||
|
@ -13,6 +18,8 @@ class Interactions {
|
||||||
/// Emitted when a slash command is created by the user.
|
/// Emitted when a slash command is created by the user.
|
||||||
late final Stream<SlashCommand> onSlashCommandCreated;
|
late final Stream<SlashCommand> onSlashCommandCreated;
|
||||||
|
|
||||||
|
final _commandHandlers = <String, SlashCommandHandlder>{};
|
||||||
|
|
||||||
/// Create new instance of the interactions class.
|
/// Create new instance of the interactions class.
|
||||||
Interactions(Nyxx client) {
|
Interactions(Nyxx client) {
|
||||||
this._client = client;
|
this._client = client;
|
||||||
|
@ -20,19 +27,43 @@ class Interactions {
|
||||||
_client.options.dispatchRawShardEvent = true;
|
_client.options.dispatchRawShardEvent = true;
|
||||||
_logger.info("Interactions ready");
|
_logger.info("Interactions ready");
|
||||||
|
|
||||||
client.onReady.listen((event) {
|
client.onReady.listen((event) async {
|
||||||
client.shardManager.rawEvent.listen((event) {
|
client.shardManager.rawEvent.listen((event) {
|
||||||
if (event.rawData["op"] as int == 0) {
|
if (event.rawData["op"] as int == _op0) {
|
||||||
if (event.rawData["t"] as String == "INTERACTION_CREATE") {
|
if (event.rawData["t"] as String == _interactionCreateCommand) {
|
||||||
_events.onSlashCommand.add(
|
_events.onSlashCommand.add(
|
||||||
InteractionEvent._new(client, event.rawData["d"] as Map<String, dynamic>),
|
InteractionEvent._new(client, event.rawData["d"] as Map<String, dynamic>),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (this._commandHandlers.isNotEmpty) {
|
||||||
|
await this.sync();
|
||||||
|
this.onSlashCommand.listen((event) async {
|
||||||
|
try {
|
||||||
|
final handler = _commandHandlers[event.interaction.name];
|
||||||
|
|
||||||
|
if (handler == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
await handler(event);
|
||||||
|
} on Error catch (e) {
|
||||||
|
this._logger.severe("Failed to execute command (${event.interaction.name})", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Registers command and handler for that command.
|
||||||
|
void registerHandler(String name, String description, List<CommandArg> args, {required SlashCommandHandlder handler, Snowflake? guild}) {
|
||||||
|
final command = this.createCommand(name, description, args, guild: guild);
|
||||||
|
this.registerCommand(command);
|
||||||
|
_commandHandlers[name] = handler;
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a command that can be registered using .registerCommand or .registerCommands
|
/// Creates a command that can be registered using .registerCommand or .registerCommands
|
||||||
///
|
///
|
||||||
/// The [name] is the name that the user can see when typing /, the [description] can also be seen in this same place. [args] are any arguments you want the user to type, you can put an empty list here is you require no arguments. If you want this to be specific to a guild you can set the [guild] param with the ID of a guild, when testing its recommended to use this as it propagates immediately while global commands can take some time.
|
/// The [name] is the name that the user can see when typing /, the [description] can also be seen in this same place. [args] are any arguments you want the user to type, you can put an empty list here is you require no arguments. If you want this to be specific to a guild you can set the [guild] param with the ID of a guild, when testing its recommended to use this as it propagates immediately while global commands can take some time.
|
||||||
|
@ -65,12 +96,15 @@ class Interactions {
|
||||||
var failed = 0;
|
var failed = 0;
|
||||||
for (final command in _commands) {
|
for (final command in _commands) {
|
||||||
if (!command.isRegistered) {
|
if (!command.isRegistered) {
|
||||||
await command._register().then((value) {
|
try {
|
||||||
this._events.onSlashCommandCreated.add(command);
|
final registeredCommand = await command._register();
|
||||||
|
this._events.onSlashCommandCreated.add(registeredCommand);
|
||||||
|
|
||||||
success++;
|
success++;
|
||||||
}).catchError(() {
|
} on HttpResponseError catch (e) {
|
||||||
|
this._logger.severe("Failed registering command: ${e.toString()}");
|
||||||
failed++;
|
failed++;
|
||||||
});
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_logger.info(
|
_logger.info(
|
||||||
|
|
|
@ -10,9 +10,8 @@ class InteractionEvent {
|
||||||
/// If the Client has sent a response to the Discord API. Once the API was received a response you cannot send another.
|
/// If the Client has sent a response to the Discord API. Once the API was received a response you cannot send another.
|
||||||
bool hasResponded = false;
|
bool hasResponded = false;
|
||||||
|
|
||||||
InteractionEvent._new(Nyxx client, Map<String, dynamic> rawJson) {
|
InteractionEvent._new(this._client, Map<String, dynamic> rawJson) {
|
||||||
this._client = client;
|
this.interaction = Interaction._new(this._client, rawJson);
|
||||||
this.interaction = Interaction._new(client, rawJson);
|
|
||||||
|
|
||||||
if (this.interaction.type == 1) {
|
if (this.interaction.type == 1) {
|
||||||
this._pong();
|
this._pong();
|
||||||
|
@ -73,7 +72,7 @@ class InteractionEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to acknowledge a Interaction and send a response. Once this is sent you can then only send ChannelMessages. You can also set showSource to also print out the command the user entered.
|
/// Used to acknowledge a Interaction and send a response. 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<void> reply({ dynamic content, EmbedBuilder? embed, bool? tts, AllowedMentions? allowedMentions, bool showSource = false, }) async {
|
Future<void> reply({ dynamic content, EmbedBuilder? embed, bool? tts, AllowedMentions? allowedMentions, bool showSource = false, bool hidden = false}) async {
|
||||||
if (DateTime.now().isBefore(this.receivedAt.add(const Duration(minutes: 15)))) {
|
if (DateTime.now().isBefore(this.receivedAt.add(const Duration(minutes: 15)))) {
|
||||||
String url;
|
String url;
|
||||||
if (hasResponded) {
|
if (hasResponded) {
|
||||||
|
@ -87,6 +86,7 @@ class InteractionEvent {
|
||||||
body: {
|
body: {
|
||||||
"type": showSource ? 4 : 3,
|
"type": showSource ? 4 : 3,
|
||||||
"data": {
|
"data": {
|
||||||
|
if (hidden) "flags": 1 << 6,
|
||||||
"content": content,
|
"content": content,
|
||||||
"embeds": embed != null ? [BuilderUtility.buildRawEmbed(embed)] : null,
|
"embeds": embed != null ? [BuilderUtility.buildRawEmbed(embed)] : null,
|
||||||
"allowed_mentions":
|
"allowed_mentions":
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
part of nyxx_interactions;
|
part of nyxx_interactions;
|
||||||
|
|
||||||
/// The Interaction data. e.g channel, guild and member
|
/// The Interaction data. e.g channel, guild and member
|
||||||
class Interaction extends SnowflakeEntity implements Disposable {
|
class Interaction extends SnowflakeEntity {
|
||||||
/// Reference to bot instance.
|
/// Reference to bot instance.
|
||||||
final Nyxx _client;
|
final Nyxx _client;
|
||||||
|
|
||||||
|
@ -27,54 +27,45 @@ class Interaction extends SnowflakeEntity implements Disposable {
|
||||||
late final String name;
|
late final String name;
|
||||||
|
|
||||||
/// Args of the interaction
|
/// Args of the interaction
|
||||||
late final Map<String, InteractionOption> args;
|
late final Iterable<InteractionOption> args;
|
||||||
|
|
||||||
Interaction._new(
|
/// Id of command
|
||||||
this._client,
|
late final Snowflake commandId;
|
||||||
Map<String, dynamic> raw,
|
|
||||||
) : super(Snowflake(raw["id"])) {
|
Interaction._new(this._client, Map<String, dynamic> raw) : super(Snowflake(raw["id"])) {
|
||||||
this.type = raw["type"] as int;
|
this.type = raw["type"] as int;
|
||||||
|
|
||||||
this.guild = CacheUtility.createCacheableGuild(
|
this.guild = CacheUtility.createCacheableGuild(
|
||||||
_client,
|
_client,
|
||||||
Snowflake(
|
Snowflake(raw["guild_id"],),
|
||||||
raw["guild_id"],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.channel = CacheUtility.createCacheableTextChannel(
|
this.channel = CacheUtility.createCacheableTextChannel(
|
||||||
_client,
|
_client,
|
||||||
Snowflake(
|
Snowflake(raw["channel_id"]),
|
||||||
raw["channel_id"],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
this.author = EntityUtility.createGuildMember(
|
this.author = EntityUtility.createGuildMember(
|
||||||
_client,
|
_client,
|
||||||
Snowflake(
|
Snowflake(raw["guild_id"]),
|
||||||
raw["guild_id"],
|
|
||||||
),
|
|
||||||
raw["member"] as Map<String, dynamic>,
|
raw["member"] as Map<String, dynamic>,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.token = raw["token"] as String;
|
this.token = raw["token"] as String;
|
||||||
this.version = raw["version"] as int;
|
this.version = raw["version"] as int;
|
||||||
this.name = raw["data"]["name"] as String;
|
this.name = raw["data"]["name"] as String;
|
||||||
this.args = _generateArgs(raw["data"] as Map<String, dynamic>);
|
this.args = _generateArgs(raw["data"] as Map<String, dynamic>);
|
||||||
|
this.commandId = Snowflake(raw["data"]["id"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, InteractionOption> _generateArgs(Map<String, dynamic> rawData) {
|
Iterable<InteractionOption> _generateArgs(Map<String, dynamic> rawData) sync* {
|
||||||
final args = <String, InteractionOption>{};
|
if (rawData["options"] == null) {
|
||||||
|
return;
|
||||||
if (rawData["options"] != null) {
|
|
||||||
final options = rawData["options"] as List;
|
|
||||||
for (final option in options) {
|
|
||||||
args[option["name"] as String] = InteractionOption._new(
|
|
||||||
option["value"] as dynamic,
|
|
||||||
(option["options"] ?? List<dynamic>.empty()) as List<Map<String, dynamic>>,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return args;
|
final options = rawData["options"] as List<dynamic>;
|
||||||
|
for (final option in options) {
|
||||||
|
yield InteractionOption._new(option as Map<String, dynamic>);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> dispose() => Future.value(null);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,17 +3,30 @@ part of nyxx_interactions;
|
||||||
/// The option given by the user when sending a command
|
/// The option given by the user when sending a command
|
||||||
class InteractionOption {
|
class InteractionOption {
|
||||||
/// The value given by the user
|
/// The value given by the user
|
||||||
final dynamic? value;
|
late final dynamic value;
|
||||||
|
|
||||||
|
/// Type of interaction
|
||||||
|
late final InteractionOption type;
|
||||||
|
|
||||||
|
/// Name of option
|
||||||
|
late final String name;
|
||||||
|
|
||||||
/// Any args under this as you can have sub commands
|
/// Any args under this as you can have sub commands
|
||||||
final Map<String, InteractionOption> args = {};
|
late final Iterable<InteractionOption> args;
|
||||||
|
|
||||||
InteractionOption._new(this.value, List<Map<String, dynamic>> rawOptions) {
|
/// Option choices
|
||||||
for (final option in rawOptions) {
|
late final Iterable<ArgChoice> choices;
|
||||||
this.args[option["name"] as String] = InteractionOption._new(
|
|
||||||
option["value"] as dynamic,
|
InteractionOption._new(Map<String, dynamic> raw) {
|
||||||
(option["options"] ?? List<Map<String, dynamic>>.empty()) as List<Map<String, dynamic>>,
|
this.value = raw["value"] as dynamic;
|
||||||
);
|
this.name = raw["name"] as String;
|
||||||
|
|
||||||
|
if (raw["options"] != null) {
|
||||||
|
this.args = (raw["options"] as List<Map<String, dynamic>>).map((e) => InteractionOption._new(e));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw["choices"] != null) {
|
||||||
|
this.choices = (raw["options"] as List<Map<String, dynamic>>).map((e) => ArgChoice(e["name"] as String, e["value"]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,30 +2,51 @@ part of nyxx_interactions;
|
||||||
|
|
||||||
/// A slash command, can only be instantiated through a method on [Interactions]
|
/// A slash command, can only be instantiated through a method on [Interactions]
|
||||||
class SlashCommand {
|
class SlashCommand {
|
||||||
|
Snowflake? _id;
|
||||||
|
|
||||||
|
Snowflake get id {
|
||||||
|
if (!this.isRegistered || _id == null) {
|
||||||
|
throw new StateError("There is no id if command is not registered");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _id!;
|
||||||
|
}
|
||||||
|
|
||||||
/// Command name to be shown to the user in the Slash Command UI
|
/// Command name to be shown to the user in the Slash Command UI
|
||||||
late final String name;
|
late final String name;
|
||||||
|
|
||||||
/// Command description shown to the user in the Slash Command UI
|
/// Command description shown to the user in the Slash Command UI
|
||||||
late final String description;
|
late final String description;
|
||||||
|
|
||||||
/// The guild that the slash Command is registered in. This can be null if its a global command.
|
/// The guild that the slash Command is registered in. This can be null if its a global command.
|
||||||
late final Cacheable<Snowflake, Guild>? guild;
|
late final Cacheable<Snowflake, Guild>? guild;
|
||||||
|
|
||||||
/// The arguments that the command takes
|
/// The arguments that the command takes
|
||||||
late final List<CommandArg> args;
|
late final List<CommandArg> args;
|
||||||
|
|
||||||
/// If the command is a global on, false if restricted to a guild.
|
/// If the command is a global on, false if restricted to a guild.
|
||||||
late final bool isGlobal;
|
bool get isGlobal => this.guild == null;
|
||||||
|
|
||||||
/// If the command has been registered with the discord api
|
/// If the command has been registered with the discord api
|
||||||
late bool isRegistered = false;
|
late bool isRegistered = false;
|
||||||
|
|
||||||
late final Nyxx _client;
|
late final Nyxx _client;
|
||||||
|
|
||||||
SlashCommand._new(this._client, this.name, this.description, this.args, {this.guild}) {
|
SlashCommand._new(this._client, this.name, this.description, this.args, {this.guild});
|
||||||
this.isGlobal = guild == null;
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<SlashCommand> _register() async {
|
Future<SlashCommand> _register() async {
|
||||||
final options = args.map((e) => e._build());
|
final options = args.map((e) => e._build()).toList();
|
||||||
|
|
||||||
|
var path = "/applications/${this._client.app.id.toString()}";
|
||||||
|
|
||||||
|
if (this.guild != null) {
|
||||||
|
path += "/guilds/${this.guild!.id}";
|
||||||
|
}
|
||||||
|
|
||||||
|
path += "/commands";
|
||||||
|
|
||||||
final response = await this._client.httpEndpoints.sendRawRequest(
|
final response = await this._client.httpEndpoints.sendRawRequest(
|
||||||
"/applications/${this._client.app.id.toString()}/commands",
|
path,
|
||||||
"POST",
|
"POST",
|
||||||
body: {"name": this.name, "description": this.description, "options": options.isNotEmpty ? options : null},
|
body: {"name": this.name, "description": this.description, "options": options.isNotEmpty ? options : null},
|
||||||
);
|
);
|
||||||
|
@ -34,6 +55,7 @@ class SlashCommand {
|
||||||
return Future.error(response);
|
return Future.error(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._id = Snowflake((response as HttpResponseSuccess).jsonBody["id"]);
|
||||||
this.isRegistered = true;
|
this.isRegistered = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,18 @@
|
||||||
part of nyxx_interactions;
|
part of nyxx_interactions;
|
||||||
|
|
||||||
/// A specified choice for a slash command argument.
|
/// A specified choice for a slash command argument.
|
||||||
class ArgChoice {
|
class ArgChoice implements Builder {
|
||||||
/// This options name.
|
/// This options name.
|
||||||
late final String name;
|
final String name;
|
||||||
|
|
||||||
/// This is the options value, must be int or string
|
/// This is the options value, must be int or string
|
||||||
late final dynamic value;
|
final dynamic value;
|
||||||
|
|
||||||
/// A Choice for the user to input in int & string args. You can only have an int or string option.
|
/// A Choice for the user to input in int & string args. You can only have an int or string option.
|
||||||
ArgChoice(this.name, dynamic value) {
|
ArgChoice(this.name, this.value) {
|
||||||
if (value is! int && value is! String) {
|
if (value is! int && value is! String) {
|
||||||
throw ArgumentError("Please send a string if its a string arg or an int if its an int arg");
|
throw ArgumentError("Please send a string if its a string arg or an int if its an int arg");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.value = value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, dynamic> _build() => {"name": this.name, "value": this.value};
|
Map<String, dynamic> _build() => {"name": this.name, "value": this.value};
|
||||||
|
|
|
@ -1,27 +1,30 @@
|
||||||
part of nyxx_interactions;
|
part of nyxx_interactions;
|
||||||
|
|
||||||
/// The type that a user should input for a [SlashArg]
|
/// The type that a user should input for a [CommandArg]
|
||||||
enum CommandArgType {
|
class CommandArgType extends IEnum<int> {
|
||||||
/// Specify an arg as a sub command
|
/// Specify an arg as a sub command
|
||||||
subCommand,
|
static const subCommand = const CommandArgType(1);
|
||||||
/// Specify an arg as a sub command group
|
/// Specify an arg as a sub command group
|
||||||
subCommandGroup,
|
static const subCommandGroup = const CommandArgType(2);
|
||||||
/// Specify an arg as a string
|
/// Specify an arg as a string
|
||||||
string,
|
static const string = const CommandArgType(3);
|
||||||
/// Specify an arg as an int
|
/// Specify an arg as an int
|
||||||
integer,
|
static const integer = const CommandArgType(4);
|
||||||
/// Specify an arg as a bool
|
/// Specify an arg as a bool
|
||||||
boolean,
|
static const boolean = const CommandArgType(5);
|
||||||
/// Specify an arg as a user e.g @HarryET#2954
|
/// Specify an arg as a user e.g @HarryET#2954
|
||||||
user,
|
static const user = const CommandArgType(6);
|
||||||
/// Specify an arg as a channel e.g. #Help
|
/// Specify an arg as a channel e.g. #Help
|
||||||
channel,
|
static const channel = const CommandArgType(7);
|
||||||
/// Specify an arg as a role e.g. @RoleName
|
/// Specify an arg as a role e.g. @RoleName
|
||||||
role,
|
static const role = const CommandArgType(8);
|
||||||
|
|
||||||
|
/// Create new instance of CommandArgType
|
||||||
|
const CommandArgType(int value) : super(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An argument for a [SlashCommand].
|
/// An argument for a [SlashCommand].
|
||||||
class CommandArg {
|
class CommandArg implements Builder {
|
||||||
/// The type of arg that will be later changed to an INT value, their values can be seen in the table below:
|
/// The type of arg that will be later changed to an INT value, their values can be seen in the table below:
|
||||||
/// | Name | Value |
|
/// | Name | Value |
|
||||||
/// |-------------------|-------|
|
/// |-------------------|-------|
|
||||||
|
@ -57,23 +60,13 @@ class CommandArg {
|
||||||
CommandArg(this.type, this.name, this.description,
|
CommandArg(this.type, this.name, this.description,
|
||||||
{this.defaultArg = false, this.required = false, this.choices, this.options});
|
{this.defaultArg = false, this.required = false, this.choices, this.options});
|
||||||
|
|
||||||
Map<String, dynamic> _build() {
|
Map<String, dynamic> _build() => {
|
||||||
final subOptions = this.options != null
|
"type": this.type.value,
|
||||||
? this.options!.map((e) => e._build())
|
|
||||||
: null;
|
|
||||||
|
|
||||||
final rawChoices = this.choices != null
|
|
||||||
? this.choices!.map((e) => e._build())
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return {
|
|
||||||
"type": (this.type.index) + 1,
|
|
||||||
"name": this.name,
|
"name": this.name,
|
||||||
"description": this.description,
|
"description": this.description,
|
||||||
"default": this.defaultArg,
|
"default": this.defaultArg,
|
||||||
"required": this.required,
|
"required": this.required,
|
||||||
"choices": rawChoices,
|
if (this.choices != null) "choices": this.choices!.map((e) => e._build()),
|
||||||
"options": subOptions
|
if (this.options != null) "options": this.options!.map((e) => e._build())
|
||||||
};
|
};
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,3 +12,7 @@ environment:
|
||||||
dependencies:
|
dependencies:
|
||||||
logging: "^1.0.0-nullsafety.0"
|
logging: "^1.0.0-nullsafety.0"
|
||||||
nyxx: "^1.1.0-dev.2"
|
nyxx: "^1.1.0-dev.2"
|
||||||
|
|
||||||
|
dependency_overrides:
|
||||||
|
nyxx:
|
||||||
|
path: "../nyxx"
|
|
@ -218,7 +218,7 @@ class Nyxx implements Disposable {
|
||||||
|
|
||||||
final errorsPort = ReceivePort();
|
final errorsPort = ReceivePort();
|
||||||
errorsPort.listen((err) {
|
errorsPort.listen((err) {
|
||||||
_logger.severe("ERROR: ${err[0]} \n ${err[1]}");
|
_logger.severe("ERROR: ${err[0]}; ${err[1]}");
|
||||||
});
|
});
|
||||||
Isolate.current.addErrorListener(errorsPort.sendPort);
|
Isolate.current.addErrorListener(errorsPort.sendPort);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1441,17 +1441,9 @@ class _HttpEndpoints implements IHttpEndpoints {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<_HttpResponse> sendRawRequest(String url, String method,
|
Future<_HttpResponse> sendRawRequest(String url, String method,
|
||||||
{dynamic body, dynamic headers}) async {
|
{dynamic body, dynamic headers}) => _httpClient
|
||||||
final response = await _httpClient
|
|
||||||
._execute(BasicRequest._new(url, method: method, body: body));
|
._execute(BasicRequest._new(url, method: method, body: body));
|
||||||
|
|
||||||
if (response is HttpResponseError) {
|
|
||||||
return Future.error(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Future.value(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<_HttpResponse> _getGatewayBot() =>
|
Future<_HttpResponse> _getGatewayBot() =>
|
||||||
_client._http._execute(BasicRequest._new("/gateway/bot"));
|
_client._http._execute(BasicRequest._new("/gateway/bot"));
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ class HttpResponseSuccess extends _HttpResponse {
|
||||||
|
|
||||||
/// Returned when client fails to execute http request.
|
/// Returned when client fails to execute http request.
|
||||||
/// Will contain reason why request failed.
|
/// Will contain reason why request failed.
|
||||||
class HttpResponseError extends _HttpResponse {
|
class HttpResponseError extends _HttpResponse implements Error {
|
||||||
/// Message why http request failed
|
/// Message why http request failed
|
||||||
late String errorMessage;
|
late String errorMessage;
|
||||||
|
|
||||||
|
@ -71,4 +71,7 @@ class HttpResponseError extends _HttpResponse {
|
||||||
@override
|
@override
|
||||||
String toString() =>
|
String toString() =>
|
||||||
"[Code: $errorCode] [Message: $errorMessage]";
|
"[Code: $errorCode] [Message: $errorMessage]";
|
||||||
|
|
||||||
|
@override
|
||||||
|
StackTrace? get stackTrace => null;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue