Implement NyxxRest. Migrate initially existing code

This commit is contained in:
Szymon Uglis 2021-02-24 01:05:18 +01:00
parent 26c5929ac4
commit 21e3cd2f95
No known key found for this signature in database
GPG key ID: 112376C5BEE91FE2
33 changed files with 290 additions and 193 deletions

View file

@ -25,9 +25,6 @@ class CommandContext {
/// Shard on which message was sent
int get shardId => this.guild != null ? this.guild!.shard.id : 0;
/// Returns shard on which message was sent
Shard get shard => this.client.shardManager.shards.toList()[shardId];
/// Substring by which command was matched
final String commandMatcher;
@ -139,7 +136,7 @@ class CommandContext {
Future<Map<IEmoji, int>> awaitEmojis(Message msg, Duration duration){
final collectedEmoji = <IEmoji, int>{};
return Future<Map<IEmoji, int>>(() async {
await for (final event in (msg.client as Nyxx).onMessageReactionAdded.where((evnt) => evnt.message != null && evnt.message!.id == msg.id)) {
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];
@ -161,7 +158,7 @@ class CommandContext {
/// Waits for first [TypingEvent] and returns it. If timed out returns null.
/// Can listen to specific user by specifying [user]
Future<TypingEvent?> waitForTyping(User user, {Duration timeout = const Duration(seconds: 30)}) =>
Future<TypingEvent?>(() => (user.client as Nyxx).onTyping.firstWhere((e) => e.user == user && e.channel == this.channel)).timeout(timeout, onTimeout: () => null);
Future<TypingEvent?>(() => client.onTyping.firstWhere((e) => e.user == user && e.channel == this.channel)).timeout(timeout, onTimeout: () => null);
/// Gets all context channel messages that satisfies [predicate].
///

View file

@ -1,5 +1,5 @@
name: nyxx_commander
version: 1.1.0-dev.6
version: 1.1.0-dev.1
description: A Discord library for Dart.
homepage: https://github.com/l7ssha/nyxx
repository: https://github.com/l7ssha/nyxx
@ -7,9 +7,13 @@ documentation: https://github.com/l7ssha/nyxx/wiki
issue_tracker: https://github.com/l7ssha/nyxx/issue
environment:
sdk: '>=2.12.0 <2.13.0'
sdk: '>=2.12.0-51.0.dev <3.0.0'
dependencies:
http: "^0.13.0"
logging: "^1.0.1"
nyxx: "^1.1.0-dev.5"
logging: "^1.0.0-nullsafety.0"
nyxx: "^1.1.0-dev.1"
dependency_overrides:
nyxx:
path: "../nyxx"

View file

@ -38,7 +38,7 @@ extension MessageResolverExtension on Message {
return "";
}
return MessageResolver(this.client,
return MessageResolver(this.client as Nyxx,
userTagHandling: userTagHandling,
roleTagHandling: roleTagHandling,
everyoneTagHandling: everyoneTagHandling,

View file

@ -1,5 +1,5 @@
name: nyxx_extensions
version: 1.1.0-dev.3
version: 1.1.0-dev.2
description: Extensions for Nyxx library
homepage: https://github.com/l7ssha/nyxx
repository: https://github.com/l7ssha/nyxx
@ -7,8 +7,12 @@ documentation: https://github.com/l7ssha/nyxx/wiki
issue_tracker: https://github.com/l7ssha/nyxx/issue
environment:
sdk: '>=2.12.0 <2.13.0'
sdk: '>=2.12.0-51.0.dev <3.0.0'
dependencies:
nyxx: "^1.1.0-dev.1"
http: "^0.13.0"
nyxx: "1.1.0-dev.4"
dependency_overrides:
nyxx:
path: "../nyxx"

View file

@ -1,5 +1,176 @@
part of nyxx;
abstract class INyxx implements Disposable {
_HttpHandler get _http;
_HttpEndpoints get _httpEndpoints;
ClientOptions get _options;
CacheOptions get _cacheOptions;
String get _token;
/// All of the guilds the bot is in. Can be empty or can miss guilds on (READY_EVENT).
Cache<Snowflake, Guild> get guilds;
/// All of the channels the bot can see.
ChannelCache get channels;
/// All of the users the bot can see. Does not have offline users
/// without `forceFetchUsers` enabled.
Cache<Snowflake, User> get users;
/// Returns handler for all available REST API action.
IHttpEndpoints get httpEndpoints => this._httpEndpoints;
/// Emitted when a successful HTTP response is received.
late final StreamController<HttpResponseEvent> _onHttpResponse;
/// Emitted when a HTTP request failed.
late final StreamController<HttpErrorEvent> _onHttpError;
/// Sent when the client is ratelimited, either by the ratelimit handler itself,
/// or when a 429 is received.
late final StreamController<RatelimitEvent> _onRatelimited;
/// Emitted when a successful HTTP response is received.
late Stream<HttpResponseEvent> onHttpResponse;
/// Emitted when a HTTP request failed.
late Stream<HttpErrorEvent> onHttpError;
/// Sent when the client is ratelimited, either by the ratelimit handler itself,
/// or when a 429 is received.
late Stream<RatelimitEvent> onRatelimited;
}
/// Lightweight client which do not start ws connections.
class NyxxRest extends INyxx {
@override
final String _token;
final DateTime _startTime = DateTime.now();
@override
late final ClientOptions _options;
@override
late final CacheOptions _cacheOptions;
@override
late final _HttpHandler _http;
@override
late final _HttpEndpoints _httpEndpoints;
/// When identifying to the gateway, you have to specify an intents parameter which
/// allows you to conditionally subscribe to pre-defined "intents", groups of events defined by Discord.
/// If you do not specify a certain intent, you will not receive any of the gateway events that are batched into that group.
/// Since api v8 its required upon connecting to gateway.
final int intents;
/// The current bot user.
late ClientUser self;
/// The bot"s OAuth2 app.
late ClientOAuth2Application app;
/// All of the guilds the bot is in. Can be empty or can miss guilds on (READY_EVENT).
@override
late final Cache<Snowflake, Guild> guilds;
/// All of the channels the bot can see.
@override
late final ChannelCache channels;
/// All of the users the bot can see. Does not have offline users
/// without `forceFetchUsers` enabled.
@override
late final Cache<Snowflake, User> users;
/// True if client is ready.
bool ready = false;
/// The current version of `nyxx`
final String version = Constants.version;
/// Logger instance
final Logger _logger = Logger("Client");
/// Gets an bot invite link with zero permissions
String get inviteLink => app.getInviteUrl();
/// Can be used to edit options after client initialised. Used by Nyxx.interactions to enable raw events
ClientOptions get options => this._options;
/// Creates and logs in a new client. If [ignoreExceptions] is true (by default is)
/// isolate will ignore all exceptions and continue to work.
NyxxRest(this._token, this.intents,
{ClientOptions? options,
CacheOptions? cacheOptions,
bool ignoreExceptions = true,
bool useDefaultLogger = true,
Level? defaultLoggerLogLevel}) {
if (useDefaultLogger) {
Logger.root.level = defaultLoggerLogLevel ?? Level.ALL;
Logger.root.onRecord.listen((LogRecord rec) {
print(
"[${rec.time}] [${rec.level.name}] [${rec.loggerName}] ${rec.message}");
});
}
this._logger.info("Starting bot with pid: $pid");
if (_token.isEmpty) {
throw MissingTokenError();
}
if (!Platform.isWindows) {
ProcessSignal.sigterm.watch().forEach((event) async {
await this.dispose();
});
}
ProcessSignal.sigint.watch().forEach((event) async {
await this.dispose();
});
if (ignoreExceptions) {
Isolate.current.setErrorsFatal(false);
final errorsPort = ReceivePort();
errorsPort.listen((err) {
_logger.severe("ERROR: ${err[0]} \n ${err[1]}");
});
Isolate.current.addErrorListener(errorsPort.sendPort);
}
this._options = options ?? ClientOptions();
this._cacheOptions = cacheOptions ?? CacheOptions();
this.guilds = _SnowflakeCache();
this.channels = ChannelCache._new();
this.users = _SnowflakeCache();
this._http = _HttpHandler._new(this);
this._httpEndpoints = _HttpEndpoints._new(this);
this._onHttpError = StreamController.broadcast();
this.onHttpError = _onHttpError.stream;
this._onHttpResponse = StreamController.broadcast();
this.onHttpResponse = _onHttpResponse.stream;
this._onRatelimited = StreamController.broadcast();
this.onRatelimited = _onRatelimited.stream;
}
@override
Future<void> dispose() async {
await this._onHttpResponse.close();
await this._onHttpError.close();
await this._onRatelimited.close();
}
}
/// The main place to start with interacting with the Discord API and creating discord bot.
/// From there you can subscribe to various [Stream]s to listen to [Events](https://github.com/l7ssha/nyxx/wiki/EventList)
/// and fetch data from API with provided methods or get cached data.
@ -17,63 +188,16 @@ part of nyxx;
/// });
/// ```
/// or setup `CommandsFramework` and `Voice`.
class Nyxx implements Disposable {
final String _token;
final DateTime _startTime = DateTime.now();
late final ClientOptions _options;
late final CacheOptions _cacheOptions;
class Nyxx extends NyxxRest {
late final _ConnectionManager _ws; // ignore: unused_field
late final _EventController _events;
late final _HttpHandler _http;
late final _HttpEndpoints _httpEndpoints;
/// When identifying to the gateway, you have to specify an intents parameter which
/// allows you to conditionally subscribe to pre-defined "intents", groups of events defined by Discord.
/// If you do not specify a certain intent, you will not receive any of the gateway events that are batched into that group.
/// Since api v8 its required upon connecting to gateway.
final int intents;
/// The current bot user.
late ClientUser self;
/// The bot"s OAuth2 app.
late ClientOAuth2Application app;
/// All of the guilds the bot is in. Can be empty or can miss guilds on (READY_EVENT).
late final Cache<Snowflake, Guild> guilds;
/// All of the channels the bot can see.
late final ChannelCache channels;
/// All of the users the bot can see. Does not have offline users
/// without `forceFetchUsers` enabled.
late final Cache<Snowflake, User> users;
/// True if client is ready.
bool ready = false;
/// The current version of `nyxx`
final String version = Constants.version;
/// Current client"s shard
late ShardManager shardManager;
/// Emitted when a shard is disconnected from the websocket.
late Stream<DisconnectEvent> onDisconnect;
/// Emitted when a successful HTTP response is received.
late Stream<HttpResponseEvent> onHttpResponse;
/// Emitted when a HTTP request failed.
late Stream<HttpErrorEvent> onHttpError;
/// Sent when the client is ratelimited, either by the ratelimit handler itself,
/// or when a 429 is received.
late Stream<RatelimitEvent> onRatelimited;
/// Emitted when the client is ready. Should be sent only once.
late Stream<ReadyEvent> onReady;
@ -177,75 +301,22 @@ class Nyxx implements Disposable {
/// Emitted when a bot removes all instances of a given emoji from the reactions of a message
late Stream<MessageReactionRemoveEmojiEvent> onMessageReactionRemoveEmoji;
/// Logger instance
final Logger _logger = Logger("Client");
/// Gets an bot invite link with zero permissions
String get inviteLink => app.getInviteUrl();
/// Can be used to edit options after client initialised. Used by Nyxx.interactions to enable raw events
ClientOptions get options => this._options;
/// Returns handler for all available REST API action.
IHttpEndpoints get httpEndpoints => this._httpEndpoints;
/// Creates and logs in a new client. If [ignoreExceptions] is true (by default is)
/// isolate will ignore all exceptions and continue to work.
Nyxx(this._token, this.intents,
Nyxx(String token, int intents,
{ClientOptions? options,
CacheOptions? cacheOptions,
bool ignoreExceptions = true,
bool useDefaultLogger = true,
Level? defaultLoggerLogLevel}) {
if (useDefaultLogger) {
Logger.root.level = defaultLoggerLogLevel ?? Level.ALL;
Logger.root.onRecord.listen((LogRecord rec) {
print(
"[${rec.time}] [${rec.level.name}] [${rec.loggerName}] ${rec.message}");
});
}
this._logger.info("Starting bot with pid: $pid");
if (_token.isEmpty) {
throw MissingTokenError();
}
if (!Platform.isWindows) {
ProcessSignal.sigterm.watch().forEach((event) async {
await this.dispose();
});
}
ProcessSignal.sigint.watch().forEach((event) async {
await this.dispose();
});
if (ignoreExceptions) {
Isolate.current.setErrorsFatal(false);
final errorsPort = ReceivePort();
errorsPort.listen((err) {
_logger.severe("ERROR: ${err[0]}; ${err[1]}");
});
Isolate.current.addErrorListener(errorsPort.sendPort);
}
this._options = options ?? ClientOptions();
this._cacheOptions = cacheOptions ?? CacheOptions();
this.guilds = _SnowflakeCache();
this.channels = ChannelCache._new();
this.users = _SnowflakeCache();
this._http = _HttpHandler._new(this);
this._httpEndpoints = _HttpEndpoints._new(this);
Level? defaultLoggerLogLevel}) :
super(token, intents, options: options, cacheOptions: cacheOptions,
ignoreExceptions: ignoreExceptions, useDefaultLogger: useDefaultLogger,
defaultLoggerLogLevel: defaultLoggerLogLevel
) {
this._events = _EventController(this);
this.onSelfMention = this
.onMessageReceived
.where((event) => event.message.mentions.any((element) => element.id == this.self.id));
.where((event) => event.message.mentions.contains(this.self));
this.onDmReceived =
this.onMessageReceived.where((event) => event.message is DMMessage);
@ -280,6 +351,29 @@ class Nyxx implements Disposable {
Future<User> fetchUser(Snowflake userId) =>
this._httpEndpoints.fetchUser(userId);
// /// Creates new guild with provided builder.
// /// Only for bots with less than 10 guilds otherwise it will return Future with error.
// ///
// /// ```
// /// var guildBuilder = GuildBuilder()
// /// ..name = "Example Guild"
// /// ..roles = [RoleBuilder()..name = "Example Role]
// /// var newGuild = await client.createGuild(guildBuilder);
// /// ```
// Future<Guild> createGuild(GuildBuilder builder) async {
// if (this.guilds.count >= 10) {
// return Future.error(ArgumentError("Guild cannot be created if bot is in 10 or more guilds"));
// }
//
// final response = await this._http._execute(BasicRequest._new("/guilds", method: "POST"));
//
// if (response is HttpResponseSuccess) {
// return Guild._new(this, response.jsonBody as Map<String, dynamic>);
// }
//
// return Future.error(response);
// }
/// Gets a webhook by its id and/or token.
/// If token is supplied authentication is not needed.
Future<Webhook> fetchWebhook(Snowflake id, {String token = ""}) =>

View file

@ -18,7 +18,7 @@ class Invite {
late final Cacheable<Snowflake, User>? targetUser;
/// Reference to bot instance
final Nyxx client;
final INyxx client;
/// Returns url to invite
String get url => "https://discord.gg/$code";
@ -93,7 +93,7 @@ class InviteWithMeta extends Invite {
return ageValidity && expiryValidity;
}
InviteWithMeta._new(Map<String, dynamic> raw, Nyxx client) : super._new(raw, client) {
InviteWithMeta._new(Map<String, dynamic> raw, INyxx client) : super._new(raw, client) {
this.createdAt = DateTime.parse(raw["created_at"] as String);
this.temporary = raw["temporary"] as bool;
this.uses = raw["uses"] as int;

View file

@ -17,7 +17,7 @@ class AuditLog {
Iterable<AuditLogEntry> filter(bool Function(AuditLogEntry) test) =>
entries.values.where(test);
AuditLog._new(Map<String, dynamic> raw, Nyxx client) {
AuditLog._new(Map<String, dynamic> raw, INyxx client) {
webhooks = {};
users = {};
entries = {};

View file

@ -22,7 +22,7 @@ class AuditLogEntry extends SnowflakeEntity {
/// The reason for the change
String? reason;
AuditLogEntry._new(Map<String, dynamic> raw, Nyxx client) : super(Snowflake(raw["id"] as String)) {
AuditLogEntry._new(Map<String, dynamic> raw, INyxx client) : super(Snowflake(raw["id"] as String)) {
this.targetId = raw["targetId"] as String;
this.changes = [

View file

@ -8,13 +8,13 @@ abstract class IChannel extends SnowflakeEntity implements Disposable {
late final ChannelType channelType;
/// Reference to client
final Nyxx client;
final INyxx client;
IChannel._new(this.client, Map<String, dynamic> raw): super(Snowflake(raw["id"])){
this.channelType = ChannelType.from(raw["type"] as int);
}
factory IChannel._deserialize(Nyxx client, Map<String, dynamic> raw, [Snowflake? guildId]) {
factory IChannel._deserialize(INyxx client, Map<String, dynamic> raw, [Snowflake? guildId]) {
final type = raw["type"] as int;
switch (type) {
@ -43,7 +43,7 @@ abstract class IChannel extends SnowflakeEntity implements Disposable {
}
class _InternalChannel extends GuildChannel {
_InternalChannel._new(Nyxx client, Map<String, dynamic> raw, [Snowflake? guildId]): super._new(client, raw, guildId);
_InternalChannel._new(INyxx client, Map<String, dynamic> raw, [Snowflake? guildId]): super._new(client, raw, guildId);
}
/// Enum for possible channel types

View file

@ -19,7 +19,7 @@ class DMChannel extends IChannel implements TextChannel {
/// Returns other user in chat if channel is not group dm. Will throw [ArgumentError] if channel is group dm.
User get participant => !this.isGroupDM ? participants.first : throw new ArgumentError("Channel is not direct DM");
DMChannel._new(Nyxx client, Map<String, dynamic> raw): super._new(client, raw) {
DMChannel._new(INyxx client, Map<String, dynamic> raw): super._new(client, raw) {
if (raw["recipients"] != null) {
this.participants = [
for (final userRaw in raw["recipients"])

View file

@ -1,5 +1,5 @@
part of nyxx;
class CategoryGuildChannel extends GuildChannel {
CategoryGuildChannel._new(Nyxx client, Map<String, dynamic> raw, [Snowflake? guildId]): super._new(client, raw, guildId);
CategoryGuildChannel._new(INyxx client, Map<String, dynamic> raw, [Snowflake? guildId]): super._new(client, raw, guildId);
}

View file

@ -19,7 +19,7 @@ abstract class GuildChannel extends IChannel {
/// Permission override for channel
late final List<PermissionsOverrides> permissionOverrides;
GuildChannel._new(Nyxx client, Map<String, dynamic> raw, [Snowflake? guildId]) : super._new(client, raw) {
GuildChannel._new(INyxx client, Map<String, dynamic> raw, [Snowflake? guildId]) : super._new(client, raw) {
this.name = raw["name"] as String;
this.position = raw["position"] as int;

View file

@ -27,7 +27,7 @@ class TextGuildChannel extends GuildChannel implements TextChannel {
// Used to create infinite typing loop
Timer? _typing;
TextGuildChannel._new(Nyxx client, Map<String, dynamic> raw, [Snowflake? guildId]) : super._new(client, raw, guildId) {
TextGuildChannel._new(INyxx client, Map<String, dynamic> raw, [Snowflake? guildId]) : super._new(client, raw, guildId) {
this.topic = raw["topic"] as String?;
this.slowModeThreshold = raw["rate_limit_per_user"] as int? ?? 0;
}

View file

@ -7,7 +7,7 @@ class VoiceGuildChannel extends GuildChannel {
/// The channel's user limit.
late final int? userLimit;
VoiceGuildChannel._new(Nyxx client, Map<String, dynamic> raw, [Snowflake? guildId]) : super._new(client, raw, guildId) {
VoiceGuildChannel._new(INyxx client, Map<String, dynamic> raw, [Snowflake? guildId]) : super._new(client, raw, guildId) {
this.bitrate = raw["bitrate"] as int?;
this.userLimit = raw["user_limit"] as int?;
}
@ -18,8 +18,12 @@ class VoiceGuildChannel extends GuildChannel {
/// Connects client to channel
void connect({bool selfMute = false, bool selfDeafen = false}) {
if (this.client is! Nyxx) {
throw new UnsupportedError("Cannot connect with NyxxRest");
}
try {
final shard = this.client.shardManager.shards.firstWhere((element) => element.guilds.contains(this.guild.id));
final shard = (this.client as Nyxx).shardManager.shards.firstWhere((element) => element.guilds.contains(this.guild.id));
shard.changeVoiceState(this.guild.id, this.id, selfMute: selfMute, selfDeafen: selfDeafen);
} on Error {
@ -29,8 +33,12 @@ class VoiceGuildChannel extends GuildChannel {
/// Disconnects use from channel.
void disconnect() {
if (this.client is! Nyxx) {
throw new UnsupportedError("Cannot connect with NyxxRest");
}
try {
final shard = this.client.shardManager.shards.firstWhere((element) => element.guilds.contains(this.guild.id));
final shard = (this.client as Nyxx).shardManager.shards.firstWhere((element) => element.guilds.contains(this.guild.id));
shard.changeVoiceState(this.guild.id, null);
} on Error {

View file

@ -8,7 +8,7 @@ class Ban {
/// Banned user
late final User user;
Ban._new(Map<String, dynamic> raw, Nyxx client) {
Ban._new(Map<String, dynamic> raw, INyxx client) {
this.reason = raw["reason"] as String;
this.user = User._new(client, raw["user"] as Map<String, dynamic>);
}

View file

@ -2,7 +2,7 @@ part of nyxx;
class Guild extends SnowflakeEntity {
/// Reference to [Nyxx] instance
Nyxx client;
final INyxx client;
/// The guild's name.
late final String name;
@ -97,7 +97,13 @@ class Guild extends SnowflakeEntity {
Role get everyoneRole => roles.values.firstWhere((r) => r.name == "@everyone");
/// Returns member object for bot user
Member? get selfMember => members[client.self.id];
Member? get selfMember {
if (this.client is! Nyxx) {
throw new UnsupportedError("Cannot use this property with NyxxRest");
}
return members[(client as Nyxx).self.id];
}
/// File upload limit for channel in bytes.
int get fileUploadLimit {
@ -115,7 +121,13 @@ class Guild extends SnowflakeEntity {
}
/// Returns this guilds shard
Shard get shard => client.shardManager.shards.firstWhere((_shard) => _shard.guilds.contains(this.id));
Shard get shard {
if (this.client is! Nyxx) {
throw new UnsupportedError("Cannot use this property with NyxxRest");
}
return (client as Nyxx).shardManager.shards.firstWhere((_shard) => _shard.guilds.contains(this.id));
}
Guild._new(this.client, Map<String, dynamic> raw, [bool guildCreate = false]) : super(Snowflake(raw["id"])) {
this.name = raw["name"] as String;

View file

@ -4,7 +4,7 @@ part of nyxx;
/// This endpoint is only for Public guilds.
class GuildPreview extends SnowflakeEntity {
/// Reference to client
final Nyxx client;
final INyxx client;
/// Guild name
late final String name;

View file

@ -2,7 +2,7 @@ part of nyxx;
class Role extends SnowflakeEntity implements Mentionable {
/// Reference to client
final Nyxx client;
final INyxx client;
/// Cachealble or guild attached to this role instance
late final Cacheable<Snowflake, Guild> guild;

View file

@ -62,7 +62,7 @@ class Webhook extends SnowflakeEntity implements IMessageAuthor {
String get tag => "";
/// Reference to [Nyxx] object
final Nyxx client;
final INyxx client;
Webhook._new(Map<String, dynamic> raw, this.client) : super(Snowflake(raw["id"] as String)) {
this.name = raw["name"] as String?;

View file

@ -32,7 +32,7 @@ class GuildEmojiPartial extends IGuildEmoji implements IEmoji {
class GuildEmoji extends GuildEmojiPartial implements IEmoji {
/// Reference to client
final Nyxx client;
final INyxx client;
/// Reference to guild where emoji belongs to
late final Cacheable<Snowflake, Guild> guild;

View file

@ -2,7 +2,7 @@ part of nyxx;
abstract class Message extends SnowflakeEntity implements Disposable {
/// Reference to bot instance
final Nyxx client;
final INyxx client;
/// The message's content.
late String content;
@ -52,7 +52,7 @@ abstract class Message extends SnowflakeEntity implements Disposable {
/// Message reply
late final ReferencedMessage? referencedMessage;
factory Message._deserialize(Nyxx client, Map<String, dynamic> raw) {
factory Message._deserialize(INyxx client, Map<String, dynamic> raw) {
if (raw["guild_id"] != null) {
return GuildMessage._new(client, raw);
}
@ -185,7 +185,7 @@ class DMMessage extends Message {
String get url => "https://discordapp.com/channels/@me"
"/${this.channel.id}/${this.id}";
DMMessage._new(Nyxx client, Map<String, dynamic> raw) : super._new(client, raw) {
DMMessage._new(INyxx client, Map<String, dynamic> raw) : super._new(client, raw) {
final user = client.users[Snowflake(raw["author"]["id"])];
if (user == null) {
@ -228,7 +228,7 @@ class GuildMessage extends Message {
/// Role mentions in this message
late final List<Cacheable<Snowflake, Role>> roleMentions;
GuildMessage._new(Nyxx client, Map<String, dynamic> raw) : super._new(client, raw) {
GuildMessage._new(INyxx client, Map<String, dynamic> raw) : super._new(client, raw) {
if (raw["message_reference"] != null) {
this.crossPostReference = MessageReference._new(
raw["message_reference"] as Map<String, dynamic>, client);

View file

@ -11,7 +11,7 @@ class MessageReference {
/// Original guild
late final Cacheable<Snowflake, Guild>? guild;
MessageReference._new(Map<String, dynamic> raw, Nyxx client) {
MessageReference._new(Map<String, dynamic> raw, INyxx client) {
this.channel = _ChannelCacheable(client, Snowflake(raw["channel_id"]));
if (raw["message_id"] != null) {

View file

@ -16,7 +16,7 @@ class ReferencedMessage {
/// True if references message exists and is available
bool get exists => !isDeleted && !isBackendFetchError;
ReferencedMessage._new(Nyxx client, Map<String, dynamic> raw) {
ReferencedMessage._new(INyxx client, Map<String, dynamic> raw) {
if (!raw.containsKey("referenced_message")) {
this.message = null;
this.isBackendFetchError = true;

View file

@ -2,7 +2,7 @@ part of nyxx;
class Member extends SnowflakeEntity {
/// Reference to client
final Nyxx client;
final INyxx client;
/// [Cacheable] for this [Guild] member
late final Cacheable<Snowflake, User> user;

View file

@ -3,7 +3,7 @@ part of nyxx;
/// Represents a single user of Discord, either a human or a bot, outside of any specific guild's context.
class User extends SnowflakeEntity with Mentionable, IMessageAuthor implements ISend {
/// Reference to client
final Nyxx client;
final INyxx client;
/// The user's username.
@override

View file

@ -33,7 +33,7 @@ class VoiceState {
/// Whether this user's camera is enabled
late final bool selfVideo;
VoiceState._new(Nyxx client, Map<String, dynamic> raw) {
VoiceState._new(INyxx client, Map<String, dynamic> raw) {
if (raw["channel_id"] != null) {
this.channel = _ChannelCacheable(client, Snowflake(raw["channel_id"]));
} else {

View file

@ -5,16 +5,6 @@ class _EventController implements Disposable {
/// Emitted when a shard is disconnected from the websocket.
late final StreamController<DisconnectEvent> onDisconnect;
/// Emitted when a successful HTTP response is received.
late final StreamController<HttpResponseEvent> onHttpResponse;
/// Emitted when a HTTP request failed.
late final StreamController<HttpErrorEvent> onHttpError;
/// Sent when the client is ratelimited, either by the ratelimit handler itself,
/// or when a 429 is received.
late final StreamController<RatelimitEvent> onRatelimited;
/// Emitted when the client is ready.
late final StreamController<ReadyEvent> onReady;
@ -116,15 +106,6 @@ class _EventController implements Disposable {
this.onDisconnect = StreamController.broadcast();
_client.onDisconnect = this.onDisconnect.stream;
this.onHttpResponse = StreamController.broadcast();
_client.onHttpResponse = this.onHttpResponse.stream;
this.onHttpError = StreamController.broadcast();
_client.onHttpError = this.onHttpError.stream;
this.onRatelimited = StreamController.broadcast();
_client.onRatelimited = this.onRatelimited.stream;
this.onReady = StreamController.broadcast();
_client.onReady = this.onReady.stream;
@ -225,9 +206,6 @@ class _EventController implements Disposable {
@override
Future<void> dispose() async {
await this.onDisconnect.close();
await this.onHttpResponse.close();
await this.onHttpError.close();
await this.onRatelimited.close();
await this.onGuildUpdate.close();
await this.onReady.close();
await this.onMessageReceived.close();

View file

@ -275,7 +275,7 @@ abstract class IHttpEndpoints {
class _HttpEndpoints implements IHttpEndpoints {
late final _HttpHandler _httpClient;
final Nyxx _client;
final INyxx _client;
_HttpEndpoints._new(this._client) {
this._httpClient = this._client._http;

View file

@ -4,7 +4,7 @@ part of nyxx;
/// Always provides [id] of entity. `download()` method tries to get entity from API and returns it upon success or
/// throws Error if something happens in the process.
abstract class Cacheable<T extends Snowflake, S extends SnowflakeEntity> {
final Nyxx _client;
final INyxx _client;
/// Id of entity
final T id;
@ -39,7 +39,7 @@ abstract class Cacheable<T extends Snowflake, S extends SnowflakeEntity> {
class _RoleCacheable extends Cacheable<Snowflake, Role> {
final Cacheable<Snowflake, Guild> guild;
_RoleCacheable(Nyxx client, Snowflake id, this.guild): super._new(client, id);
_RoleCacheable(INyxx client, Snowflake id, this.guild): super._new(client, id);
@override
Future<Role> download() async => this._fetchGuildRole();
@ -68,7 +68,7 @@ class _RoleCacheable extends Cacheable<Snowflake, Role> {
}
class _ChannelCacheable<T extends IChannel> extends Cacheable<Snowflake, T> {
_ChannelCacheable(Nyxx client, Snowflake id): super._new(client, id);
_ChannelCacheable(INyxx client, Snowflake id): super._new(client, id);
@override
T? getFromCache() => this._client.channels[this.id] as T?;
@ -78,7 +78,7 @@ class _ChannelCacheable<T extends IChannel> extends Cacheable<Snowflake, T> {
}
class _GuildCacheable extends Cacheable<Snowflake, Guild> {
_GuildCacheable(Nyxx client, Snowflake id): super._new(client, id);
_GuildCacheable(INyxx client, Snowflake id): super._new(client, id);
@override
Guild? getFromCache() => this._client.guilds[this.id];
@ -88,7 +88,7 @@ class _GuildCacheable extends Cacheable<Snowflake, Guild> {
}
class _UserCacheable extends Cacheable<Snowflake, User> {
_UserCacheable(Nyxx client, Snowflake id): super._new(client, id);
_UserCacheable(INyxx client, Snowflake id): super._new(client, id);
@override
Future<User> download() => _client._httpEndpoints.fetchUser(this.id);
@ -100,7 +100,7 @@ class _UserCacheable extends Cacheable<Snowflake, User> {
class _MemberCacheable extends Cacheable<Snowflake, Member> {
final Cacheable<Snowflake, Guild> guild;
_MemberCacheable(Nyxx client, Snowflake id, this.guild): super._new(client, id);
_MemberCacheable(INyxx client, Snowflake id, this.guild): super._new(client, id);
@override
Future<Member> download() =>
@ -121,7 +121,7 @@ class _MemberCacheable extends Cacheable<Snowflake, Member> {
class _MessageCacheable<U extends TextChannel> extends Cacheable<Snowflake, Message> {
final Cacheable<Snowflake, U> channel;
_MessageCacheable(Nyxx client, Snowflake id, this.channel) : super._new(client, id);
_MessageCacheable(INyxx client, Snowflake id, this.channel) : super._new(client, id);
@override
Future<Message> download() async {

View file

@ -22,7 +22,7 @@ class _HttpBucket {
final waitTime = resetAt!.millisecondsSinceEpoch - now.millisecondsSinceEpoch;
if (waitTime > 0) {
_httpHandler.client._events.onRatelimited.add(RatelimitEvent._new(request, true));
_httpHandler.client._onRatelimited.add(RatelimitEvent._new(request, true));
_httpHandler._logger.warning(
"Rate limited internally on endpoint: ${request.uri}. Trying to send request again in $waitTime ms...");
@ -49,7 +49,7 @@ class _HttpBucket {
final responseBody = jsonDecode(await response.stream.bytesToString());
final retryAfter = ((responseBody["retry_after"] as double) * 1000).round();
_httpHandler.client._events.onRatelimited.add(RatelimitEvent._new(request, false, response));
_httpHandler.client._onRatelimited.add(RatelimitEvent._new(request, false, response));
_httpHandler._logger.warning(
"Rate limited via 429 on endpoint: ${request.uri}. Trying to send request again in $retryAfter ms...");

View file

@ -6,7 +6,7 @@ class _HttpHandler {
final Logger _logger = Logger("Http");
late final _HttpClient _httpClient;
final Nyxx client;
final INyxx client;
_HttpHandler._new(this.client) {
this._noRateBucket = _HttpBucket(Uri.parse("noratelimit"), this);
@ -38,14 +38,14 @@ class _HttpHandler {
final responseSuccess = HttpResponseSuccess._new(response);
await responseSuccess._finalize();
client._events.onHttpResponse.add(HttpResponseEvent._new(responseSuccess));
client._onHttpResponse.add(HttpResponseEvent._new(responseSuccess));
return responseSuccess;
}
final responseError = HttpResponseError._new(response);
await responseError._finalize();
client._events.onHttpError.add(HttpErrorEvent._new(responseError));
client._onHttpError.add(HttpErrorEvent._new(responseError));
return responseError;
}
}

View file

@ -6,7 +6,7 @@ class _HttpClient extends http.BaseClient {
final http.Client _innerClient = http.Client();
// ignore: public_member_api_docs
_HttpClient(Nyxx client) {
_HttpClient(INyxx client) {
this._authHeader = {
"Authorization" : "Bot ${client._token}"
};

View file

@ -1,5 +1,5 @@
name: nyxx
version: 1.1.0-dev.6
version: 1.1.0-dev.3
description: A Discord library for Dart.
homepage: https://github.com/l7ssha/nyxx
repository: https://github.com/l7ssha/nyxx
@ -7,12 +7,12 @@ documentation: https://github.com/l7ssha/nyxx/wiki
issue_tracker: https://github.com/l7ssha/nyxx/issue
environment:
sdk: '>=2.12.0 <2.13.0'
sdk: '>=2.12.0-51.0.dev <3.0.0'
dependencies:
logging: "^1.0.0-nullsafety.0"
http: "^0.13.0"
logging: "^1.0.1"
path: "^1.8.0"
path: "^1.8.0-nullsafety.3"
dev_dependencies:
test: "^1.16.8"
test: "^1.16.2"