123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475 |
- #if !BESTHTTP_DISABLE_SOCKETIO
- using System;
- using System.Collections.Generic;
- namespace BestHTTP.SocketIO
- {
- using BestHTTP;
- using BestHTTP.SocketIO.Events;
-
-
-
- public sealed class Socket : ISocket
- {
- #region Public Properties
-
-
-
- public SocketManager Manager { get; private set; }
-
-
-
- public string Namespace { get; private set; }
-
-
-
- public string Id { get; private set; }
-
-
-
- public bool IsOpen { get; private set; }
-
-
-
- public bool AutoDecodePayload { get; set; }
- #endregion
- #region Privates
-
-
-
- private Dictionary<int, SocketIOAckCallback> AckCallbacks;
-
-
-
- private EventTable EventCallbacks;
-
-
-
- private List<object> arguments = new List<object>();
- #endregion
-
-
-
- internal Socket(string nsp, SocketManager manager)
- {
- this.Namespace = nsp;
- this.Manager = manager;
- this.IsOpen = false;
- this.AutoDecodePayload = true;
- this.EventCallbacks = new EventTable(this);
- }
- #region Socket Handling
-
-
-
- void ISocket.Open()
- {
-
- if (Manager.State == SocketManager.States.Open)
- OnTransportOpen(Manager.Socket, null);
- else
- {
-
- Manager.Socket.Off(EventNames.Connect, OnTransportOpen);
- Manager.Socket.On(EventNames.Connect, OnTransportOpen);
- if (Manager.Options.AutoConnect && Manager.State == SocketManager.States.Initial)
- Manager.Open();
- }
- }
-
-
-
- public void Disconnect()
- {
- (this as ISocket).Disconnect(true);
- }
-
-
-
- void ISocket.Disconnect(bool remove)
- {
-
- if (IsOpen)
- {
- Packet packet = new Packet(TransportEventTypes.Message, SocketIOEventTypes.Disconnect, this.Namespace, string.Empty);
- (Manager as IManager).SendPacket(packet);
-
- IsOpen = false;
- (this as ISocket).OnPacket(packet);
- }
- if (AckCallbacks != null)
- AckCallbacks.Clear();
- if (remove)
- {
- EventCallbacks.Clear();
- (Manager as IManager).Remove(this);
- }
- }
- #endregion
- #region Emit Implementations
- public Socket Emit(string eventName, params object[] args)
- {
- return Emit(eventName, null, args);
- }
- public Socket Emit(string eventName, SocketIOAckCallback callback, params object[] args)
- {
- bool blackListed = EventNames.IsBlacklisted(eventName);
- if (blackListed)
- throw new ArgumentException("Blacklisted event: " + eventName);
- arguments.Clear();
- arguments.Add(eventName);
-
-
- List<byte[]> attachments = null;
- if (args != null && args.Length > 0)
- {
- int idx = 0;
- for (int i = 0; i < args.Length; ++i)
- {
- byte[] binData = args[i] as byte[];
- if (binData != null)
- {
- if (attachments == null)
- attachments = new List<byte[]>();
- Dictionary<string, object> placeholderObj = new Dictionary<string, object>(2);
- placeholderObj.Add(Packet.Placeholder, true);
- placeholderObj.Add("num", idx++);
- arguments.Add(placeholderObj);
- attachments.Add(binData);
- }
- else
- arguments.Add(args[i]);
- }
- }
- string payload = null;
- try
- {
- payload = Manager.Encoder.Encode(arguments);
- }
- catch(Exception ex)
- {
- (this as ISocket).EmitError(SocketIOErrors.Internal, "Error while encoding payload: " + ex.Message + " " + ex.StackTrace);
- return this;
- }
-
- arguments.Clear();
- if (payload == null)
- throw new ArgumentException("Encoding the arguments to JSON failed!");
- int id = 0;
- if (callback != null)
- {
- id = Manager.NextAckId;
- if (AckCallbacks == null)
- AckCallbacks = new Dictionary<int, SocketIOAckCallback>();
- AckCallbacks[id] = callback;
- }
- Packet packet = new Packet(TransportEventTypes.Message,
- attachments == null ? SocketIOEventTypes.Event : SocketIOEventTypes.BinaryEvent,
- this.Namespace,
- payload,
- 0,
- id);
- if (attachments != null)
- packet.Attachments = attachments;
- (Manager as IManager).SendPacket(packet);
- return this;
- }
- public Socket EmitAck(Packet originalPacket, params object[] args)
- {
- if (originalPacket == null)
- throw new ArgumentNullException("originalPacket == null!");
- if (
- (originalPacket.SocketIOEvent != SocketIOEventTypes.Event && originalPacket.SocketIOEvent != SocketIOEventTypes.BinaryEvent))
- throw new ArgumentException("Wrong packet - you can't send an Ack for a packet with id == 0 and SocketIOEvent != Event or SocketIOEvent != BinaryEvent!");
- arguments.Clear();
- if (args != null && args.Length > 0)
- arguments.AddRange(args);
- string payload = null;
- try
- {
- payload = Manager.Encoder.Encode(arguments);
- }
- catch (Exception ex)
- {
- (this as ISocket).EmitError(SocketIOErrors.Internal, "Error while encoding payload: " + ex.Message + " " + ex.StackTrace);
- return this;
- }
- if (payload == null)
- throw new ArgumentException("Encoding the arguments to JSON failed!");
- Packet packet = new Packet(TransportEventTypes.Message,
- originalPacket.SocketIOEvent == SocketIOEventTypes.Event ? SocketIOEventTypes.Ack : SocketIOEventTypes.BinaryAck,
- this.Namespace,
- payload,
- 0,
- originalPacket.Id);
- (Manager as IManager).SendPacket(packet);
- return this;
- }
- #endregion
- #region On Implementations
-
-
-
- public void On(string eventName, SocketIOCallback callback)
- {
- EventCallbacks.Register(eventName, callback, false, this.AutoDecodePayload);
- }
- public void On(SocketIOEventTypes type, SocketIOCallback callback)
- {
- string eventName = EventNames.GetNameFor(type);
- EventCallbacks.Register(eventName, callback, false, this.AutoDecodePayload);
- }
- public void On(string eventName, SocketIOCallback callback, bool autoDecodePayload)
- {
- EventCallbacks.Register(eventName, callback, false, autoDecodePayload);
- }
- public void On(SocketIOEventTypes type, SocketIOCallback callback, bool autoDecodePayload)
- {
- string eventName = EventNames.GetNameFor(type);
- EventCallbacks.Register(eventName, callback, false, autoDecodePayload);
- }
- #endregion
- #region Once Implementations
- public void Once(string eventName, SocketIOCallback callback)
- {
- EventCallbacks.Register(eventName, callback, true, this.AutoDecodePayload);
- }
- public void Once(SocketIOEventTypes type, SocketIOCallback callback)
- {
- EventCallbacks.Register(EventNames.GetNameFor(type), callback, true, this.AutoDecodePayload);
- }
- public void Once(string eventName, SocketIOCallback callback, bool autoDecodePayload)
- {
- EventCallbacks.Register(eventName, callback, true, autoDecodePayload);
- }
- public void Once(SocketIOEventTypes type, SocketIOCallback callback, bool autoDecodePayload)
- {
- EventCallbacks.Register(EventNames.GetNameFor(type), callback, true, autoDecodePayload);
- }
- #endregion
- #region Off Implementations
-
-
-
- public void Off()
- {
- EventCallbacks.Clear();
- }
-
-
-
- public void Off(string eventName)
- {
- EventCallbacks.Unregister(eventName);
- }
-
-
-
- public void Off(SocketIOEventTypes type)
- {
- Off(EventNames.GetNameFor(type));
- }
-
-
-
- public void Off(string eventName, SocketIOCallback callback)
- {
- EventCallbacks.Unregister(eventName, callback);
- }
-
-
-
- public void Off(SocketIOEventTypes type, SocketIOCallback callback)
- {
- EventCallbacks.Unregister(EventNames.GetNameFor(type), callback);
- }
- #endregion
- #region Packet Handling
-
-
-
- void ISocket.OnPacket(Packet packet)
- {
-
- switch(packet.SocketIOEvent)
- {
- case SocketIOEventTypes.Connect:
- this.Id = this.Namespace != "/" ? this.Namespace + "#" + this.Manager.Handshake.Sid : this.Manager.Handshake.Sid;
- break;
- case SocketIOEventTypes.Disconnect:
- if (IsOpen)
- {
- IsOpen = false;
- EventCallbacks.Call(EventNames.GetNameFor(SocketIOEventTypes.Disconnect), packet);
- Disconnect();
- }
- break;
-
- case SocketIOEventTypes.Error:
- bool success = false;
- object result = JSON.Json.Decode(packet.Payload, ref success);
- if (success)
- {
- var errDict = result as Dictionary<string, object>;
- Error err;
- if (errDict != null && errDict.ContainsKey("code"))
- err = new Error((SocketIOErrors)Convert.ToInt32(errDict["code"]), errDict["message"] as string);
- else
- err = new Error(SocketIOErrors.Custom, packet.Payload);
- EventCallbacks.Call(EventNames.GetNameFor(SocketIOEventTypes.Error), packet, err);
- return;
- }
- break;
- }
-
- EventCallbacks.Call(packet);
-
- if ((packet.SocketIOEvent == SocketIOEventTypes.Ack || packet.SocketIOEvent == SocketIOEventTypes.BinaryAck) && AckCallbacks != null)
- {
- SocketIOAckCallback ackCallback = null;
- if (AckCallbacks.TryGetValue(packet.Id, out ackCallback) &&
- ackCallback != null)
- {
- try
- {
- ackCallback(this, packet, this.AutoDecodePayload ? packet.Decode(Manager.Encoder) : null);
- }
- catch (Exception ex)
- {
- HTTPManager.Logger.Exception("Socket", "ackCallback", ex);
- }
- }
- AckCallbacks.Remove(packet.Id);
- }
- }
- #endregion
-
-
-
- void ISocket.EmitEvent(SocketIOEventTypes type, params object[] args)
- {
- (this as ISocket).EmitEvent(EventNames.GetNameFor(type), args);
- }
-
-
-
- void ISocket.EmitEvent(string eventName, params object[] args)
- {
- if (!string.IsNullOrEmpty(eventName))
- EventCallbacks.Call(eventName, null, args);
- }
- void ISocket.EmitError(SocketIOErrors errCode, string msg)
- {
- (this as ISocket).EmitEvent(SocketIOEventTypes.Error, new Error(errCode, msg));
- }
- #region Private Helper Functions
-
-
-
- private void OnTransportOpen(Socket socket, Packet packet, params object[] args)
- {
-
- if (this.Namespace != "/")
- (Manager as IManager).SendPacket(new Packet(TransportEventTypes.Message, SocketIOEventTypes.Connect, this.Namespace, string.Empty));
-
- IsOpen = true;
- }
- #endregion
- }
- }
- #endif
|