EventTable.cs 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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 descriptor
  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. List<EventDescriptor> events;
  66. if (Table.TryGetValue(eventName, out events))
  67. {
  68. if (HTTPManager.Logger.Level <= BestHTTP.Logger.Loglevels.All)
  69. HTTPManager.Logger.Verbose("EventTable", string.Format("Call - {0} ({1})", eventName, events.Count));
  70. for (int i = 0; i < events.Count; ++i)
  71. events[i].Call(Socket, packet, args);
  72. }
  73. else
  74. {
  75. if (HTTPManager.Logger.Level <= BestHTTP.Logger.Loglevels.All)
  76. HTTPManager.Logger.Verbose("EventTable", string.Format("Call - {0} (0)", eventName));
  77. }
  78. }
  79. /// <summary>
  80. /// This function will get the eventName from the packet's Payload, and optionally will decode it from Json.
  81. /// </summary>
  82. public void Call(Packet packet)
  83. {
  84. string eventName = packet.DecodeEventName();
  85. string typeName = packet.SocketIOEvent != SocketIOEventTypes.Unknown ? EventNames.GetNameFor(packet.SocketIOEvent) : EventNames.GetNameFor(packet.TransportEvent);
  86. object[] args = null;
  87. if (!HasSubsciber(eventName) && !HasSubsciber(typeName))
  88. return;
  89. // If this is an Event or BinaryEvent message, or we have a subscriber with AutoDecodePayload, then
  90. // we have to decode the packet's Payload.
  91. if (packet.TransportEvent == TransportEventTypes.Message && (packet.SocketIOEvent == SocketIOEventTypes.Event || packet.SocketIOEvent == SocketIOEventTypes.BinaryEvent) && ShouldDecodePayload(eventName))
  92. args = packet.Decode(Socket.Manager.Encoder);
  93. // call event callbacks registered for 'eventName'
  94. if (!string.IsNullOrEmpty(eventName))
  95. Call(eventName, packet, args);
  96. if (!packet.IsDecoded && ShouldDecodePayload(typeName))
  97. args = packet.Decode(Socket.Manager.Encoder);
  98. // call event callbacks registered for 'typeName'
  99. if (!string.IsNullOrEmpty(typeName))
  100. Call(typeName, packet, args);
  101. }
  102. /// <summary>
  103. /// Remove all event -> delegate association.
  104. /// </summary>
  105. public void Clear()
  106. {
  107. Table.Clear();
  108. }
  109. #region Private Helpers
  110. /// <summary>
  111. /// Returns true, if for the given event name there are at least one event that needs a decoded
  112. /// </summary>
  113. /// <param name="eventName"></param>
  114. /// <returns></returns>
  115. private bool ShouldDecodePayload(string eventName)
  116. {
  117. List<EventDescriptor> events;
  118. // If we find at least one EventDescriptor with AutoDecodePayload == true, we have to
  119. // decode the whole payload
  120. if (Table.TryGetValue(eventName, out events))
  121. for (int i = 0; i < events.Count; ++i)
  122. if (events[i].AutoDecodePayload && events[i].Callbacks.Count > 0)
  123. return true;
  124. return false;
  125. }
  126. private bool HasSubsciber(string eventName)
  127. {
  128. return Table.ContainsKey(eventName);
  129. }
  130. #endregion
  131. }
  132. }
  133. #endif