Removed auto-sharding. Closes #21
This commit is contained in:
parent
7429576bf7
commit
b263836af7
|
@ -27,8 +27,6 @@ Starting from version `1.0.0` of nyxx, library requires `Dart 2.0+`. You can use
|
|||
Nyxx works on the command line, in the browser, and on mobile devices.
|
||||
- **Fine Control** <br>
|
||||
Nyxx allows you to control every outgoing HTTP request or WebSocket message.
|
||||
- **Internal Sharding** <br>
|
||||
Nyxx automatically spawns shards for your bot, but you can override this and spawn a custom number of shards. Internal sharding means that all of your bots shards are managed in one script, and there is no need for communication between shards.
|
||||
- **Complete** <br>
|
||||
Nyxx supports nearly all Discord API endpoints.
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ void setupBot(SendPort remotePort) {
|
|||
// Listen to all incoming messages via Dart Stream
|
||||
client.onMessage.listen((MessageEvent e) {
|
||||
remotePort.send(
|
||||
"${client.shards.length};${client.guilds.count};${client.uptime.inSeconds}");
|
||||
"${client.shards};${client.guilds.count};${client.uptime.inSeconds}");
|
||||
|
||||
if (e.message.content == "oofping") {
|
||||
e.message.channel.send(content: "Pong!");
|
||||
|
|
|
@ -7,10 +7,10 @@ Logger _logger = Logger.detached("Voice Service");
|
|||
Future<void> sendFakeOp4(VoiceChannel channel,
|
||||
{bool mute = false, bool deafen = false, Guild guild}) async {
|
||||
if (guild != null) {
|
||||
guild.shard.send(
|
||||
guild.client.shard.send(
|
||||
"VOICE_STATE_UPDATE", _Opcode4(guild, channel, mute, deafen)._build());
|
||||
} else {
|
||||
channel.guild.shard.send("VOICE_STATE_UPDATE",
|
||||
channel.guild.client.shard.send("VOICE_STATE_UPDATE",
|
||||
_Opcode4(channel.guild, channel, mute, deafen)._build());
|
||||
}
|
||||
}
|
||||
|
@ -80,7 +80,7 @@ class VoiceService {
|
|||
try {
|
||||
transport.WebSocket.connect(_wsPath, headers: {
|
||||
"Authorization": _password,
|
||||
"Num-Shards": client.shards.length,
|
||||
"Num-Shards": client.shards,
|
||||
"User-Id": client.app.id.toString()
|
||||
}).then((wc) {
|
||||
this._webSocket = wc;
|
||||
|
|
|
@ -43,7 +43,7 @@ class Player {
|
|||
_onTrackError = StreamController.broadcast();
|
||||
onTrackError = _onTrackError.stream;
|
||||
|
||||
_guild.shard.send(
|
||||
_guild.client.shard.send(
|
||||
"VOICE_STATE_UPDATE", _Opcode4(_guild, channel, false, false)._build());
|
||||
|
||||
_currentState = (await _manager.client.onVoiceStateUpdate.first).state;
|
||||
|
@ -81,7 +81,7 @@ class Player {
|
|||
Future<void> changeChannel(VoiceChannel channel,
|
||||
{bool muted = false, bool deafen = false}) {
|
||||
currentChannel = channel;
|
||||
_guild.shard.send("VOICE_STATE_UPDATE",
|
||||
_guild.client.shard.send("VOICE_STATE_UPDATE",
|
||||
_Opcode4(_guild, channel, muted, deafen)._build());
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ class Player {
|
|||
|
||||
/// Disconnect from channel. Closes all unneeded connections.
|
||||
Future<void> disconnect() async {
|
||||
_guild.shard.send(
|
||||
_guild.client.shard.send(
|
||||
"VOICE_STATE_UPDATE", _Opcode4(_guild, null, false, false)._build());
|
||||
await stop();
|
||||
_manager._webSocket.add(jsonEncode(_SimpleOp("destroy", _guild)._build()));
|
||||
|
@ -133,7 +133,7 @@ class Player {
|
|||
op = _OpPause(_guild, true).build();
|
||||
|
||||
_manager._webSocket.add(jsonEncode(op));
|
||||
_guild.shard.send(
|
||||
_guild.client.shard.send(
|
||||
"VOICE_STATE_UPDATE",
|
||||
_Opcode4(_guild, currentChannel, !_currentState.selfMute,
|
||||
_currentState.selfDeaf)
|
||||
|
|
|
@ -3,15 +3,12 @@ part of nyxx;
|
|||
/// Optional client settings which can be used when creating new instance
|
||||
/// of client. It allows to tune up client to your needs.
|
||||
class ClientOptions {
|
||||
List<int> _shardIds;
|
||||
|
||||
/// Whether or not to disable @everyone and @here mentions at a global level.
|
||||
/// **It means client won't send any of these. It doesn't mean filtering guild messages.**
|
||||
bool disableEveryone;
|
||||
|
||||
/// Whether or not to automatically shard the client if the default shard
|
||||
/// values are untouched.
|
||||
bool autoShard;
|
||||
/// The index of this shard
|
||||
int shardIndex;
|
||||
|
||||
/// The total number of shards.
|
||||
int shardCount;
|
||||
|
@ -33,15 +30,10 @@ class ClientOptions {
|
|||
/// Makes a new `ClientOptions` object.
|
||||
ClientOptions(
|
||||
{this.disableEveryone = false,
|
||||
this.autoShard = false,
|
||||
this.shardIndex = 0,
|
||||
this.shardCount = 1,
|
||||
this.messageCacheSize = 400,
|
||||
this.forceFetchMembers = false,
|
||||
this.cacheMembers = true,
|
||||
this.largeThreshold = 50}) {
|
||||
if (!autoShard && shardCount > 1)
|
||||
this._shardIds = Iterable.generate(shardCount, (i) => i).toList();
|
||||
else
|
||||
this._shardIds = const [0];
|
||||
}
|
||||
this.largeThreshold = 50});
|
||||
}
|
||||
|
|
|
@ -47,9 +47,7 @@ class Nyxx implements Disposable {
|
|||
/// The current version of `nyxx`
|
||||
String version = _Constants.version;
|
||||
|
||||
/// The client's internal shards. By default shards are setup automatically by gateway,
|
||||
/// however this can be changed by [ClientOptions]
|
||||
Map<int, Shard> shards;
|
||||
Shard shard;
|
||||
|
||||
/// Generic Stream for message like events. It includes added reactions, and message deletions.
|
||||
/// For received messages refer to [onMessageReceived]
|
||||
|
@ -218,7 +216,6 @@ class Nyxx implements Disposable {
|
|||
this.guilds = _SnowflakeCache();
|
||||
this.channels = ChannelCache._new();
|
||||
this.users = _SnowflakeCache();
|
||||
this.shards = Map<int, Shard>();
|
||||
|
||||
this._http = Http._new(this);
|
||||
this._events = _EventController(this);
|
||||
|
@ -329,12 +326,13 @@ class Nyxx implements Disposable {
|
|||
}
|
||||
|
||||
/// Closes websocket connections and cleans everything up.
|
||||
Future<void> close() async => dispose();
|
||||
Future<void> close() async => await dispose();
|
||||
|
||||
int get shards => this._options.shardCount;
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
//for (var shard in this.shards.values) await shard._socket.close(1000);
|
||||
|
||||
await shard.dispose();
|
||||
await guilds.dispose();
|
||||
await users.dispose();
|
||||
await guilds.dispose();
|
||||
|
|
|
@ -4,7 +4,7 @@ part of nyxx;
|
|||
/// Guild sharding is entirely user controlled, and requires no state-sharing between separate connections to operate.
|
||||
///
|
||||
/// Shard is basically represents single websocket connection to gateway. Each shard can operate on up to 2500 guilds.
|
||||
class Shard {
|
||||
class Shard implements Disposable {
|
||||
/// The shard id.
|
||||
int id;
|
||||
|
||||
|
@ -27,6 +27,7 @@ class Shard {
|
|||
String _sessionId;
|
||||
StreamController<Shard> _onReady;
|
||||
StreamController<Shard> _onDisconnect;
|
||||
bool _reconnect = true;
|
||||
|
||||
Logger _logger = Logger("Websocket");
|
||||
|
||||
|
@ -372,12 +373,7 @@ class Shard {
|
|||
this._heartbeatTimer.cancel();
|
||||
_logger.severe(
|
||||
"Shard [$id] disconnected. Error code: [${this._socket.closeCode}] | Error message: [${this._socket.closeReason}]");
|
||||
|
||||
/*if (this._socket.closeCode == null) {
|
||||
_logger.severe("Exitting. Null close code");
|
||||
exit(1);
|
||||
}*/
|
||||
|
||||
|
||||
/// Dispose on error
|
||||
for (var guild in this.guilds.values) {
|
||||
guild.dispose();
|
||||
|
@ -390,10 +386,12 @@ class Shard {
|
|||
break;
|
||||
case 4007:
|
||||
case 4009:
|
||||
this._connect(true);
|
||||
if(this._reconnect)
|
||||
this._connect(true);
|
||||
break;
|
||||
default:
|
||||
Timer(const Duration(seconds: 2), () => this._connect(false, true));
|
||||
if(this._reconnect)
|
||||
Timer(const Duration(seconds: 2), () => this._connect(false, true));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -401,4 +399,11 @@ class Shard {
|
|||
.add(DisconnectEvent._new(this, this._socket.closeCode));
|
||||
this._onDisconnect.add(this);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() async {
|
||||
this._reconnect = false;
|
||||
await this._socket.close(1000);
|
||||
return Null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,24 +14,14 @@ class _WS {
|
|||
_client._http._headers['Authorization'] = "Bot ${_client._token}";
|
||||
_client._http.send("GET", "/gateway/bot").then((HttpResponse r) {
|
||||
this.gateway = r.body['url'] as String;
|
||||
if (_client._options.autoShard) {
|
||||
_client._options._shardIds = [];
|
||||
_client._options.shardCount = r.body['shards'] as int;
|
||||
for (int i = 0; i < _client._options.shardCount; i++) {
|
||||
setupShard(i);
|
||||
}
|
||||
} else {
|
||||
for (int shardId in _client._options._shardIds) {
|
||||
setupShard(shardId);
|
||||
}
|
||||
}
|
||||
setupShard(_client._options.shardIndex);
|
||||
this.connectShard(0);
|
||||
});
|
||||
}
|
||||
|
||||
void setupShard(int shardId) {
|
||||
Shard shard = Shard._new(this, shardId);
|
||||
_client.shards[shard.id] = shard;
|
||||
_client.shard = shard;
|
||||
|
||||
shard.onReady.listen((Shard s) {
|
||||
if (!_client.ready) {
|
||||
|
@ -41,9 +31,7 @@ class _WS {
|
|||
}
|
||||
|
||||
void connectShard(int index) {
|
||||
_client.shards.values.toList()[index]._connect(false, true);
|
||||
if (index + 1 != _client._options._shardIds.length)
|
||||
Timer(Duration(seconds: 6), () => connectShard(index + 1));
|
||||
_client.shard._connect(false, true);
|
||||
}
|
||||
|
||||
void testReady() {
|
||||
|
@ -59,10 +47,8 @@ class _WS {
|
|||
}
|
||||
|
||||
bool match2() {
|
||||
for (var shard in _client.shards.values) {
|
||||
if (!shard.ready) {
|
||||
return false;
|
||||
}
|
||||
if (!_client.shard.ready) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -30,14 +30,11 @@ class ClientUser extends User {
|
|||
/// Updates the client's presence
|
||||
ClientUser setPresence(
|
||||
{String status, bool afk = false, Presence game, DateTime since}) {
|
||||
client.shards.forEach((int id, Shard shard) {
|
||||
shard.setPresence(status: status, afk: afk, game: game, since: since);
|
||||
});
|
||||
|
||||
client.shard.setPresence(status: status, afk: afk, game: game, since: since);
|
||||
return this;
|
||||
}
|
||||
|
||||
/// Allows to set status for each shard based on shard state.
|
||||
/// Allows to set status for shard based on shard state.
|
||||
///
|
||||
/// ```
|
||||
/// client.setPresenceForShard((shard) {
|
||||
|
@ -45,7 +42,7 @@ class ClientUser extends User {
|
|||
/// });
|
||||
/// ```
|
||||
void setPresenceForShard(Function(Shard shard) func) {
|
||||
for (var shard in client.shards.values) func(shard);
|
||||
func(client.shard);
|
||||
}
|
||||
|
||||
/// Allows to get [Member] objects for all guilds for bot user.
|
||||
|
|
|
@ -79,9 +79,6 @@ class Guild extends SnowflakeEntity implements Disposable, Nameable {
|
|||
/// Permission of current(bot) user in this guild
|
||||
Permissions currentUserPermissions;
|
||||
|
||||
/// The shard that the guild is on.
|
||||
Shard shard;
|
||||
|
||||
/// Users state cache
|
||||
Cache<Snowflake, VoiceState> voiceStates;
|
||||
|
||||
|
@ -124,9 +121,6 @@ class Guild extends SnowflakeEntity implements Disposable, Nameable {
|
|||
});
|
||||
}
|
||||
|
||||
this.shard = client.shards[
|
||||
(int.parse(this.id.toString()) >> 22) % client._options.shardCount];
|
||||
|
||||
if (guildCreate) {
|
||||
this.members = _SnowflakeCache();
|
||||
this.channels = ChannelCache._new();
|
||||
|
@ -591,13 +585,14 @@ class Guild extends SnowflakeEntity implements Disposable, Nameable {
|
|||
}
|
||||
|
||||
@override
|
||||
Future<void> dispose() => Future(() {
|
||||
channels.dispose();
|
||||
members.dispose();
|
||||
roles.dispose();
|
||||
emojis.dispose();
|
||||
voiceStates.dispose();
|
||||
});
|
||||
Future<Null> dispose() async {
|
||||
await channels.dispose();
|
||||
await members.dispose();
|
||||
await roles.dispose();
|
||||
await emojis.dispose();
|
||||
await voiceStates.dispose();
|
||||
return null;
|
||||
}
|
||||
|
||||
@override
|
||||
String get nameString => "Guild ${this.name} [${this.id}]";
|
||||
|
|
|
@ -128,7 +128,7 @@ void main() {
|
|||
|
||||
assert(bot.channels.count > 0);
|
||||
assert(bot.users.count > 0);
|
||||
assert(bot.shards.length == 1);
|
||||
assert(bot.shards == 1);
|
||||
assert(bot.ready);
|
||||
assert(bot.inviteLink != null);
|
||||
|
||||
|
|
Loading…
Reference in a new issue