using Maki.Structures.Channels;
using Maki.Structures.Gateway;
using Maki.Structures.Guilds;
using Maki.Structures.Messages;
using Maki.Structures.Presences;
using Maki.Structures.Users;
using System;
using System.Collections.Generic;
using System.Linq;
namespace Maki.Gateway
{
///
/// Gateway connection shard manager
///
class GatewayShardClient : IDisposable
{
///
/// Managed (active) shards
///
private readonly List Shards = new List();
private readonly object Lock = new object();
///
/// Parent DiscordClient instance
///
private Discord Client;
///
/// Number of active managed shards
///
public int ShardCount
=> Shards.Count;
///
/// Constructor
///
/// Parent DiscordClient instance
public GatewayShardClient(Discord client)
=> Client = client;
///
/// Creates a new Gateway Shard
///
/// Id of the shard
/// New Gateway Shard
public GatewayShard Create(int id)
{
GatewayShard shard = new GatewayShard(id, Client);
shard.OnSocketPayload += Shard_OnSocketPayload;
lock (Lock)
Shards.Add(shard);
return shard;
}
private void Shard_OnSocketPayload(GatewayShard shard, GatewayPayload payload)
{
switch (payload.OPCode)
{
case GatewayOPCode.Dispatch:
switch (payload.Name)
{
#region Call
case "CALL_CREATE":
OnCallCreate?.Invoke(shard);
break;
case "CALL_DELETE":
OnCallDelete?.Invoke(shard);
break;
case "CALL_UPDATE":
OnCallUpdate?.Invoke(shard);
break;
case "VOICE_SERVER_UPDATE":
OnVoiceServerUpdate?.Invoke(shard);
break;
case "VOICE_STATE_UPDATE":
OnVoiceStateUpdate?.Invoke(shard);
break;
#endregion
#region Channel
case "CHANNEL_CREATE":
OnChannelCreate?.Invoke(shard, payload.DataAs());
break;
case "CHANNEL_DELETE":
OnChannelDelete?.Invoke(shard, payload.DataAs());
break;
case "CHANNEL_PINS_ACK":
OnChannelPinsAck?.Invoke(shard);
break;
case "CHANNEL_PINS_UPDATE":
OnChannelPinsUpdate?.Invoke(shard);
break;
case "CHANNEL_RECIPIENT_ADD":
OnChannelRecipientAdd?.Invoke(shard);
break;
case "CHANNEL_RECIPIENT_REMOVE":
OnChannelRecipientRemove?.Invoke(shard);
break;
case "CHANNEL_UPDATE":
OnChannelUpdate?.Invoke(shard, payload.DataAs());
break;
#endregion
#region Guild
case "GUILD_BAN_ADD":
OnGuildBanAdd?.Invoke(shard, payload.DataAs());
break;
case "GUILD_BAN_REMOVE":
OnGuildBanRemove?.Invoke(shard, payload.DataAs());
break;
case "GUILD_CREATE":
OnGuildCreate?.Invoke(shard, payload.DataAs());
break;
case "GUILD_DELETE":
OnGuildDelete?.Invoke(shard, payload.DataAs());
break;
case "GUILD_EMOJIS_UPDATE":
OnGuildEmojisUpdate?.Invoke(shard, payload.DataAs());
break;
case "GUILD_INTEGRATIONS_UPDATE":
OnGuildIntegrationsUpdate?.Invoke(shard, payload.DataAs());
break;
case "GUILD_MEMBER_ADD":
OnGuildMemberAdd?.Invoke(shard, payload.DataAs());
break;
case "GUILD_MEMBER_UPDATE":
OnGuildMemberUpdate?.Invoke(shard, payload.DataAs());
break;
case "GUILD_MEMBER_REMOVE":
OnGuildMemberRemove?.Invoke(shard, payload.DataAs());
break;
case "GUILD_MEMBERS_CHUNK":
OnGuildMembersChunk?.Invoke(shard, payload.DataAs());
break;
case "GUILD_ROLE_CREATE":
OnGuildRoleCreate?.Invoke(shard, payload.DataAs());
break;
case "GUILD_ROLE_UPDATE":
OnGuildRoleUpdate?.Invoke(shard, payload.DataAs());
break;
case "GUILD_ROLE_DELETE":
OnGuildRoleDelete?.Invoke(shard, payload.DataAs());
break;
case "GUILD_UPDATE":
OnGuildUpdate?.Invoke(shard, payload.DataAs());
break;
#endregion
#region Message
case "MESSAGE_ACK":
OnMessageAck?.Invoke(shard);
break;
case "MESSAGE_CREATE":
OnMessageCreate?.Invoke(shard, payload.DataAs());
break;
case "MESSAGE_DELETE":
OnMessageDelete?.Invoke(shard, payload.DataAs());
break;
case "MESSAGE_DELETE_BULK":
OnMessageDeleteBulk?.Invoke(shard);
break;
case "MESSAGE_REACTION_ADD":
OnMessageReactionAdd?.Invoke(shard);
break;
case "MESSAGE_REACTION_REMOVE":
OnMessageReactionRemove?.Invoke(shard);
break;
case "MESSAGE_REACTIONS_REMOVE_ALL":
OnMessageReactionsRemoveAll?.Invoke(shard);
break;
case "MESSAGE_UPDATE":
OnMessageUpdate?.Invoke(shard, payload.DataAs());
break;
#endregion
#region Presence
case "TYPING_START":
OnTypingStart?.Invoke(shard, payload.DataAs());
break;
case "PRESENCE_UPDATE":
OnPresenceUpdate?.Invoke(shard, payload.DataAs());
break;
case "PRESENCES_REPLACE":
OnPresencesReplace?.Invoke(shard);
break;
#endregion
#region Relations
case "FRIEND_SUGGESTION_DELETE":
OnFriendSuggestionDelete?.Invoke(shard);
break;
case "RELATIONSHIP_ADD":
OnRelationshipAdd?.Invoke(shard);
break;
case "RELATIONSHIP_REMOVE":
OnRelationshipRemove?.Invoke(shard);
break;
#endregion
#region State
case "READY":
OnReady?.Invoke(shard, payload.DataAs());
break;
case "RESUMED":
OnResumed?.Invoke(shard);
break;
#endregion
#region User
case "USER_UPDATE":
OnUserUpdate?.Invoke(shard, payload.DataAs());
break;
case "USER_NOTE_UPDATE":
OnUserNoteUpdate?.Invoke(shard);
break;
case "USER_SETTINGS_UPDATE":
OnUserSettingsUpdate?.Invoke(shard);
break;
#endregion
#if DEBUG
default:
Console.WriteLine($"Unknown payload type: {payload.Name}");
break;
#endif
}
break;
}
}
///
/// Destroys a Gateway Shard
///
/// Shard to destroy
public void Destroy(GatewayShard shard)
{
lock (Lock)
Shards.Remove(shard);
// Disconnect and Dispose are called separately so OnSocketClose is called properly
shard.Disconnect();
shard.OnSocketPayload -= Shard_OnSocketPayload;
shard.Dispose();
}
///
/// Destroys all shards
///
public void Disconnect()
{
lock (Lock)
Shards.ToList().ForEach(x => Destroy(x));
}
#region Events
public event Action OnCallCreate;
public event Action OnCallDelete;
public event Action OnCallUpdate;
public event Action OnVoiceServerUpdate;
public event Action OnVoiceStateUpdate;
public event Action OnChannelCreate;
public event Action OnChannelDelete;
public event Action OnChannelPinsAck;
public event Action OnChannelPinsUpdate;
public event Action OnChannelRecipientAdd;
public event Action OnChannelRecipientRemove;
public event Action OnChannelUpdate;
public event Action OnGuildBanAdd;
public event Action OnGuildBanRemove;
public event Action OnGuildCreate;
public event Action OnGuildDelete;
public event Action OnGuildEmojisUpdate;
public event Action OnGuildIntegrationsUpdate;
public event Action OnGuildMemberAdd;
public event Action OnGuildMemberUpdate;
public event Action OnGuildMemberRemove;
public event Action OnGuildMembersChunk;
public event Action OnGuildRoleCreate;
public event Action OnGuildRoleUpdate;
public event Action OnGuildRoleDelete;
public event Action OnGuildUpdate;
public event Action OnMessageAck;
public event Action OnMessageCreate;
public event Action OnMessageDelete;
public event Action OnMessageDeleteBulk;
public event Action OnMessageReactionAdd;
public event Action OnMessageReactionRemove;
public event Action OnMessageReactionsRemoveAll;
public event Action OnMessageUpdate;
public event Action OnTypingStart;
public event Action OnPresenceUpdate;
public event Action OnPresencesReplace;
public event Action OnFriendSuggestionDelete;
public event Action OnRelationshipAdd;
public event Action OnRelationshipRemove;
public event Action OnReady;
public event Action OnResumed;
public event Action OnUserUpdate;
public event Action OnUserNoteUpdate;
public event Action OnUserSettingsUpdate;
#endregion
#region IDisposable
private bool IsDisposed = false;
///
/// Releases all unmanaged resources used by this object
///
private void Dispose(bool disposing)
{
if (IsDisposed)
return;
IsDisposed = true;
Disconnect();
if (disposing)
GC.SuppressFinalize(this);
}
~GatewayShardClient()
=> Dispose(false);
public void Dispose()
=> Dispose(true);
#endregion
}
}