[WIP] Added missing methods to shard manager, redone emojis, code formatting
[ci skip]
This commit is contained in:
parent
a628903f43
commit
472e65d8d4
|
@ -203,7 +203,7 @@ class Nyxx implements Disposable {
|
|||
this._events = _EventController(this);
|
||||
this.onSelfMention = this
|
||||
.onMessageReceived
|
||||
.where((event) => event.message.mentions.any((mentionedUser) => mentionedUser == this.self));
|
||||
.where((event) => event.message.mentions.contains(this.self));
|
||||
this.onDmReceived = this
|
||||
.onMessageReceived
|
||||
.where((event) => event.message.channel is DMChannel || event.message.channel is GroupDMChannel);
|
||||
|
@ -230,7 +230,9 @@ class Nyxx implements Disposable {
|
|||
|
||||
/// Returns guild with given [guildId]
|
||||
Future<Guild> getGuild(Snowflake guildId, [bool useCache = true]) async {
|
||||
if (this.guilds.hasKey(guildId) && useCache) return this.guilds[guildId]!;
|
||||
if (this.guilds.hasKey(guildId) && useCache) {
|
||||
return this.guilds[guildId]!;
|
||||
}
|
||||
|
||||
final response = await _http._execute(BasicRequest._new("/guilds/$guildId"));
|
||||
|
||||
|
@ -248,7 +250,9 @@ class Nyxx implements Disposable {
|
|||
/// var channel = await client.getChannel<TextChannel>(Snowflake("473853847115137024"));
|
||||
/// ```
|
||||
Future<T> getChannel<T extends Channel>(Snowflake id, [bool useCache = true]) async {
|
||||
if (this.channels.hasKey(id) && useCache) return this.channels[id] as T;
|
||||
if (this.channels.hasKey(id) && useCache) {
|
||||
return this.channels[id] as T;
|
||||
}
|
||||
|
||||
final response = await this._http._execute(BasicRequest._new("/channels/${id.toString()}"));
|
||||
|
||||
|
@ -268,7 +272,9 @@ class Nyxx implements Disposable {
|
|||
/// var user = client.getUser(Snowflake("302359032612651009"));
|
||||
/// ``
|
||||
Future<User?> getUser(Snowflake id, [bool useCache = true]) async {
|
||||
if (this.users.hasKey(id) && useCache) return this.users[id];
|
||||
if (this.users.hasKey(id) && useCache) {
|
||||
return this.users[id];
|
||||
}
|
||||
|
||||
final response = await this._http._execute(BasicRequest._new("/users/${id.toString()}"));
|
||||
|
||||
|
@ -321,19 +327,18 @@ class Nyxx implements Disposable {
|
|||
/// var inv = client.getInvite("YMgffU8");
|
||||
/// ```
|
||||
Future<Invite> getInvite(String code) async {
|
||||
final r = await this._http._execute(BasicRequest._new("/invites/$code"));
|
||||
final response = await this._http._execute(BasicRequest._new("/invites/$code"));
|
||||
|
||||
if (r is HttpResponseSuccess) {
|
||||
return Invite._new(r.jsonBody as Map<String, dynamic>, this);
|
||||
if (response is HttpResponseSuccess) {
|
||||
return Invite._new(response.jsonBody as Map<String, dynamic>, this);
|
||||
}
|
||||
|
||||
return Future.error(r);
|
||||
return Future.error(response);
|
||||
}
|
||||
|
||||
/// Returns number of shards
|
||||
int get shards => this.shardManager._shards.length;
|
||||
|
||||
/*
|
||||
/// Sets presence for bot.
|
||||
///
|
||||
/// Code below will display bot presence as `Playing Super duper game`:
|
||||
|
@ -349,9 +354,9 @@ class Nyxx implements Disposable {
|
|||
/// ```
|
||||
/// `url` property in `Activity` can be only set when type is set to `streaming`
|
||||
void setPresence({UserStatus? status, bool? afk, Activity? game, DateTime? since}) {
|
||||
this.shard.setPresence(status: status, afk: afk, game: game, since: since);
|
||||
this.shardManager.setPresence(status: status, afk: afk, game: game, since: since);
|
||||
}
|
||||
*/
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
await shardManager.dispose();
|
||||
|
|
|
@ -20,11 +20,21 @@ class ShardManager implements Disposable {
|
|||
final int _numShards;
|
||||
final Map<int, Shard> _shards = {};
|
||||
|
||||
/// List of shards
|
||||
Iterable<Shard> get shards => List.unmodifiable(_shards.values);
|
||||
|
||||
/// Starts shard manager
|
||||
ShardManager(this._ws, this._numShards) {
|
||||
_connect(_numShards - 1);
|
||||
}
|
||||
|
||||
/// Sets presences on every shard
|
||||
void setPresence({UserStatus? status, bool? afk, Activity? game, DateTime? since}) {
|
||||
for (final shard in shards) {
|
||||
shard.setPresence(status: status, afk: afk, game: game, since: since);
|
||||
}
|
||||
}
|
||||
|
||||
void _connect(int shardId) {
|
||||
if(shardId < 0) {
|
||||
return;
|
||||
|
@ -55,6 +65,9 @@ class Shard implements Disposable {
|
|||
/// Reference to [ShardManager]
|
||||
ShardManager manager;
|
||||
|
||||
/// List of handled guild ids
|
||||
final List<Snowflake> guilds = [];
|
||||
|
||||
late final Isolate _shardIsolate; // Reference to isolate
|
||||
late final Stream<dynamic> _receiveStream; // Broadcast stream on which data from isolate is received
|
||||
late final ReceivePort _receivePort; // Port on which data from isolate is received
|
||||
|
@ -86,6 +99,64 @@ class Shard implements Disposable {
|
|||
this.sendPort.send({"cmd": "SEND", "data" : {"op": opCode, "d": d}});
|
||||
}
|
||||
|
||||
/// Allows to set presence for current shard.
|
||||
void setPresence({UserStatus? status, bool? afk, Activity? game, DateTime? since}) {
|
||||
final packet = <String, dynamic> {
|
||||
"status": (status != null) ? status.toString() : UserStatus.online.toString(),
|
||||
"afk": (afk != null) ? afk : false,
|
||||
if (game != null)
|
||||
"game": <String, dynamic>{
|
||||
"name": game.name,
|
||||
"type": game.type.value,
|
||||
if (game.type == ActivityType.streaming) "url": game.url
|
||||
},
|
||||
"since": (since != null) ? since.millisecondsSinceEpoch : null
|
||||
};
|
||||
|
||||
this.send(OPCodes.statusUpdate, packet);
|
||||
}
|
||||
|
||||
/// Syncs all guilds
|
||||
void guildSync() => this.send(OPCodes.guildSync, this.guilds.map((e) => e.toString()));
|
||||
|
||||
/// Allows to request members objects from gateway
|
||||
/// [guild] can be either Snowflake or Iterable<Snowflake>
|
||||
void requestMembers(/* Snowflake|Iterable<Snowflake> */ dynamic guild,
|
||||
{String? query, Iterable<Snowflake>? userIds, int limit = 0, bool presences = false, String? nonce}) {
|
||||
if (query != null && userIds != null) {
|
||||
throw Exception("Both `query` and userIds cannot be specified.");
|
||||
}
|
||||
|
||||
dynamic guildPayload;
|
||||
|
||||
if (guild is Snowflake) {
|
||||
if(!this.guilds.contains(guild)) {
|
||||
throw Exception("Cannot request member for guild on wrong shard");
|
||||
}
|
||||
|
||||
guildPayload = guild.toString();
|
||||
} else if (guild is Iterable<Snowflake>) {
|
||||
if(!this.guilds.any((element) => guild.contains(element))) {
|
||||
throw Exception("Cannot request member for guild on wrong shard");
|
||||
}
|
||||
|
||||
guildPayload = guild.map((e) => e.toString()).toList();
|
||||
} else {
|
||||
throw Exception("guild has to be either Snowflake or Iterable<Snowflake>");
|
||||
}
|
||||
|
||||
final payload = <String, dynamic>{
|
||||
"guild_id": guildPayload,
|
||||
if (query != null) "query": query,
|
||||
if (userIds != null) "user_ids": userIds.map((e) => e.toString()).toList(),
|
||||
"limit": limit,
|
||||
"presences": presences,
|
||||
if (nonce != null) "nonce": nonce
|
||||
};
|
||||
|
||||
this.send(OPCodes.requestGuildMember, payload);
|
||||
}
|
||||
|
||||
void _heartbeat() {
|
||||
this.send(OPCodes.heartbeat, _sequence);
|
||||
}
|
||||
|
@ -219,7 +290,9 @@ class Shard implements Disposable {
|
|||
break;
|
||||
|
||||
case "GUILD_CREATE":
|
||||
manager._ws._client._events.onGuildCreate.add(GuildCreateEvent._new(msg, manager._ws._client));
|
||||
final event = GuildCreateEvent._new(msg, manager._ws._client);
|
||||
this.guilds.add(event.guild.id);
|
||||
manager._ws._client._events.onGuildCreate.add(event);
|
||||
break;
|
||||
|
||||
case "GUILD_UPDATE":
|
||||
|
@ -363,7 +436,11 @@ Future<void> _shardHandler(SendPort shardPort) async {
|
|||
_socket = ws;
|
||||
_socket!.listen((data) {
|
||||
shardPort.send({ "cmd" : "DATA", "jsonData" : _decodeBytes(data), "resume" : resume});
|
||||
}, onError: (err) => shardPort.send({ "cmd" : "ERROR", "error": err.toString()}));
|
||||
}, onDone: () => print("DONE ----------------------- ${ws.closeCode}"),
|
||||
onError: (err) {
|
||||
print(err);
|
||||
shardPort.send({ "cmd" : "ERROR", "error": err.toString()});
|
||||
});
|
||||
}, onError: (_, __) => Future.delayed(const Duration(seconds: 2), _connect));
|
||||
}
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
late final int systemChannelFlags;
|
||||
|
||||
/// Channel where "PUBLIC" guilds display rules and/or guidelines
|
||||
late final CacheGuildChannel? rulesChannel;
|
||||
late final IGuildChannel? rulesChannel;
|
||||
|
||||
/// The guild owner's ID
|
||||
late final User? owner;
|
||||
|
@ -92,7 +92,7 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
|
||||
/// the id of the channel where admins and moderators
|
||||
/// of "PUBLIC" guilds receive notices from Discord
|
||||
late final CacheGuildChannel? publicUpdatesChannel;
|
||||
late final IGuildChannel? publicUpdatesChannel;
|
||||
|
||||
/// Permission of current(bot) user in this guild
|
||||
Permissions? currentUserPermissions;
|
||||
|
@ -229,11 +229,11 @@ class Guild extends SnowflakeEntity implements Disposable {
|
|||
}
|
||||
|
||||
if (raw["rules_channel_id"] != null) {
|
||||
this.rulesChannel = this.channels[Snowflake(raw["rules_channel_id"])] as CacheGuildChannel?;
|
||||
this.rulesChannel = this.channels[Snowflake(raw["rules_channel_id"])] as IGuildChannel;
|
||||
}
|
||||
|
||||
if (raw["public_updates_channel_id"] != null) {
|
||||
this.publicUpdatesChannel = this.channels[Snowflake(raw["public_updates_channel_id"])] as CacheGuildChannel?;
|
||||
this.publicUpdatesChannel = this.channels[Snowflake(raw["public_updates_channel_id"])] as IGuildChannel?;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ part of nyxx;
|
|||
/// Represents emoji. Subclasses provides abstraction to custom emojis(like [GuildEmoji]).
|
||||
abstract class Emoji {
|
||||
/// Emojis name.
|
||||
String name;
|
||||
final String? name;
|
||||
|
||||
Emoji._new(this.name);
|
||||
|
||||
|
|
|
@ -1,10 +1,38 @@
|
|||
part of nyxx;
|
||||
|
||||
abstract class IGuildEmoji extends Emoji {
|
||||
abstract class IGuildEmoji extends Emoji implements SnowflakeEntity {
|
||||
/// True if emoji is partial.
|
||||
final bool partial;
|
||||
|
||||
IGuildEmoji._new(String name, this.partial) : super._new(name);
|
||||
/// Snowflake id of emoji
|
||||
@override
|
||||
late final Snowflake id;
|
||||
|
||||
@override
|
||||
DateTime get createdAt => id.timestamp;
|
||||
|
||||
IGuildEmoji._new(Map<String, dynamic> raw, this.partial) : super._new(raw["name"] as String?) {
|
||||
this.id = Snowflake(raw["id"] as String);
|
||||
}
|
||||
}
|
||||
|
||||
class PartialGuildEmoji extends IGuildEmoji {
|
||||
PartialGuildEmoji._new(Map<String, dynamic> raw) : super._new(raw, true);
|
||||
|
||||
/// Encodes Emoji to API format
|
||||
@override
|
||||
String encode() => "$id";
|
||||
|
||||
/// Formats Emoji to message format
|
||||
@override
|
||||
String format() => "<:$id>";
|
||||
|
||||
/// Returns cdn url to emoji
|
||||
String get cdnUrl => "https://cdn.discordapp.com/emojis/${this.id}.png";
|
||||
|
||||
/// Returns encoded string ready to send via message.
|
||||
@override
|
||||
String toString() => format();
|
||||
}
|
||||
|
||||
/// Emoji object. Handles Unicode emojis and custom ones.
|
||||
|
@ -22,10 +50,6 @@ class GuildEmoji extends IGuildEmoji implements SnowflakeEntity, GuildEntity {
|
|||
@override
|
||||
late final Snowflake guildId;
|
||||
|
||||
/// Snowflake id of emoji
|
||||
@override
|
||||
late final Snowflake id;
|
||||
|
||||
/// Roles which can use this emote
|
||||
late final Iterable<IRole> roles;
|
||||
|
||||
|
@ -39,8 +63,7 @@ class GuildEmoji extends IGuildEmoji implements SnowflakeEntity, GuildEntity {
|
|||
late final bool animated;
|
||||
|
||||
/// Creates full emoji object
|
||||
GuildEmoji._new(Map<String, dynamic> raw, this.guildId, this.client) : super._new(raw["name"] as String, false) {
|
||||
this.id = Snowflake(raw["id"] as String);
|
||||
GuildEmoji._new(Map<String, dynamic> raw, this.guildId, this.client) : super._new(raw, false) {
|
||||
this.guild = client.guilds[this.guildId];
|
||||
|
||||
this.requireColons = raw["require_colons"] as bool? ?? false;
|
||||
|
|
|
@ -6,14 +6,14 @@ class UnicodeEmoji extends Emoji {
|
|||
UnicodeEmoji(String code) : super._new(code);
|
||||
|
||||
/// Returns Emoji
|
||||
String get code => this.name;
|
||||
String get code => this.name!;
|
||||
|
||||
/// Returns runes of emoji
|
||||
Runes get runes => this.name.runes;
|
||||
Runes get runes => this.name!.runes;
|
||||
|
||||
/// Encodes Emoji so that can be used in messages.
|
||||
@override
|
||||
String encode() => this.name;
|
||||
String encode() => this.name!;
|
||||
|
||||
/// Returns encoded string ready to send via message.
|
||||
@override
|
||||
|
|
|
@ -85,7 +85,7 @@ class GuildMemberRemoveEvent {
|
|||
/// Sent when a member is updated.
|
||||
class GuildMemberUpdateEvent {
|
||||
/// The member after the update if member is updated.
|
||||
late final CacheMember? member;
|
||||
late final IMember? member;
|
||||
|
||||
/// User if user is updated. Will be null if member is not null.
|
||||
late final User? user;
|
||||
|
@ -97,16 +97,16 @@ class GuildMemberUpdateEvent {
|
|||
return;
|
||||
}
|
||||
|
||||
final member = guild.members[Snowflake(raw["d"]["user"]["id"])];
|
||||
this.member = guild.members[Snowflake(raw["d"]["user"]["id"])];
|
||||
|
||||
if (member == null) {
|
||||
if (this.member == null || this.member is! CacheMember) {
|
||||
return;
|
||||
}
|
||||
|
||||
final nickname = raw["d"]["nickname"] as String?;
|
||||
final roles = (raw["d"]["roles"] as List<dynamic>).map((str) => guild.roles[Snowflake(str)]!).toList();
|
||||
|
||||
if (this.member!._updateMember(nickname, roles)) {
|
||||
if ((this.member as CacheMember)._updateMember(nickname, roles)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -104,8 +104,7 @@ abstract class MessageReactionEvent {
|
|||
if (json["d"]["emoji"]["id"] == null) {
|
||||
this.emoji = UnicodeEmoji(json["d"]["emoji"]["name"] as String);
|
||||
} else {
|
||||
// TODO: emojis stuff
|
||||
//this.emoji = GuildEmoji._partial(json["d"]["emoji"] as Map<String, dynamic>);
|
||||
this.emoji = PartialGuildEmoji._new(json["d"]["emoji"] as Map<String, dynamic>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue