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 } }