EventTable.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #if !BESTHTTP_DISABLE_SOCKETIO
  2. using System.Collections.Generic;
  3. namespace BestHTTP.SocketIO.Events
  4. {
  5. /// <summary>
  6. /// This class helps keep track and maintain EventDescriptor instances and dispatching packets to the right delegates.
  7. /// </summary>
  8. internal sealed class EventTable
  9. {
  10. #region Privates
  11. /// <summary>
  12. /// The Socket that this EventTable is bound to.
  13. /// </summary>
  14. private Socket Socket { get; set; }
  15. /// <summary>
  16. /// The 'EventName -> List of events' mapping.
  17. /// </summary>
  18. private Dictionary<string, List<EventDescriptor>> Table = new Dictionary<string, List<EventDescriptor>>();
  19. #endregion
  20. /// <summary>
  21. /// Constructor to create an instance and bind it to a socket.
  22. /// </summary>
  23. public EventTable(Socket socket)
  24. {
  25. this.Socket = socket;
  26. }
  27. /// <summary>
  28. /// Register a callback to a name with the given metadata.
  29. /// </summary>
  30. public void Register(string eventName, SocketIOCallback callback, bool onlyOnce, bool autoDecodePayload)
  31. {
  32. List<EventDescriptor> events;
  33. if (!Table.TryGetValue(eventName, out events))
  34. Table.Add(eventName, events = new List<EventDescriptor>(1));
  35. // Find a matching desriptor
  36. var desc = events.Find((d) => d.OnlyOnce == onlyOnce && d.AutoDecodePayload == autoDecodePayload);
  37. // If not found, create one
  38. if (desc == null)
  39. events.Add(new EventDescriptor(onlyOnce, autoDecodePayload, callback));
  40. else // if found, add the new callback
  41. desc.Callbacks.Add(callback);
  42. }
  43. /// <summary>
  44. /// Removes all events that registered for the given name.
  45. /// </summary>
  46. public void Unregister(string eventName)
  47. {
  48. Table.Remove(eventName);
  49. }
  50. /// <summary>
  51. ///
  52. /// </summary>
  53. public void Unregister(string eventName, SocketIOCallback callback)
  54. {
  55. List<EventDescriptor> events;
  56. if (Table.TryGetValue(eventName, out events))
  57. for (int i = 0; i < events.Count; ++i)
  58. events[i].Callbacks.Remove(callback);
  59. }
  60. /// <summary>
  61. /// Will call the delegates that associated to the given eventName.
  62. /// </summary>
  63. public void Call(string eventName, Packet packet, params object[] args)
  64. {
  65. if (HTTPManager.Logger.Level <= BestHTTP.Logger.Loglevels.All)
  66. HTTPManager.Logger.Verbose("EventTable", "Call - " + eventName);
  67. List<EventDescriptor> events;
  68. if (Table.TryGetValue(eventName, out events))
  69. for (int i = 0; i < events.Count; ++i)
  70. events[i].Call(Socket, packet, args);
  71. }
  72. /// <summary>
  73. /// This function will get the eventName from the packet's Payload, and optionally will decode it from Json.
  74. /// </summary>
  75. public void Call(Packet packet)
  76. {
  77. string eventName = packet.DecodeEventName();
  78. string typeName = packet.SocketIOEvent != SocketIOEventTypes.Unknown ? EventNames.GetNameFor(packet.SocketIOEvent) : EventNames.GetNameFor(packet.TransportEvent);
  79. object[] args = null;
  80. if (!HasSubsciber(eventName) && !HasSubsciber(typeName))
  81. return;
  82. // If this is an Event or BinaryEvent message, or we have a subscriber with AutoDecodePayload, then
  83. // we have to decode the packet's Payload.
  84. if (packet.TransportEvent == TransportEventTypes.Message && (packet.SocketIOEvent == SocketIOEventTypes.Event || packet.SocketIOEvent == SocketIOEventTypes.BinaryEvent) && ShouldDecodePayload(eventName))
  85. args = packet.Decode(Socket.Manager.Encoder);
  86. // call event callbacks registered for 'eventName'
  87. if (!string.IsNullOrEmpty(eventName))
  88. Call(eventName, packet, args);
  89. if (!packet.IsDecoded && ShouldDecodePayload(typeName))
  90. args = packet.Decode(Socket.Manager.Encoder);
  91. // call event callbacks registered for 'typeName'
  92. if (!string.IsNullOrEmpty(typeName))
  93. Call(typeName, packet, args);
  94. }
  95. /// <summary>
  96. /// Remove all event -> delegate association.
  97. /// </summary>
  98. public void Clear()
  99. {
  100. Table.Clear();
  101. }
  102. #region Private Helpers
  103. /// <summary>
  104. /// Returns true, if for the given event name there are at least one event that needs a decoded
  105. /// </summary>
  106. /// <param name="eventName"></param>
  107. /// <returns></returns>
  108. private bool ShouldDecodePayload(string eventName)
  109. {
  110. List<EventDescriptor> events;
  111. // If we find at least one EventDescriptor with AutoDecodePayload == true, we have to
  112. // decode the whole payload
  113. if (Table.TryGetValue(eventName, out events))
  114. for (int i = 0; i < events.Count; ++i)
  115. if (events[i].AutoDecodePayload && events[i].Callbacks.Count > 0)
  116. return true;
  117. return false;
  118. }
  119. private bool HasSubsciber(string eventName)
  120. {
  121. return Table.ContainsKey(eventName);
  122. }
  123. #endregion
  124. }
  125. }
  126. #endif