#if !BESTHTTP_DISABLE_SOCKETIO using System; using System.Text; using PlatformSupport.Collections.ObjectModel; #if !NETFX_CORE using PlatformSupport.Collections.Specialized; #else using System.Collections.Specialized; #endif namespace BestHTTP.SocketIO { public delegate void HTTPRequestCallbackDelegate(SocketManager manager, HTTPRequest request); public enum SupportedSocketIOVersions { Unknown, v2, v3 } public sealed class SocketOptions { #region Properties /// /// The SocketManager will try to connect with this transport. /// public Transports.TransportTypes ConnectWith { get; set; } /// /// Whether to reconnect automatically after a disconnect (default true) /// public bool Reconnection { get; set; } /// /// Number of attempts before giving up (default Int.MaxValue) /// public int ReconnectionAttempts { get; set; } /// /// How long to initially wait before attempting a new reconnection (default 1000ms). /// Affected by +/- RandomizationFactor, for example the default initial delay will be between 500ms to 1500ms. /// public TimeSpan ReconnectionDelay { get; set; } /// /// Maximum amount of time to wait between reconnections (default 5000ms). /// Each attempt increases the reconnection delay along with a randomization as above. /// public TimeSpan ReconnectionDelayMax { get; set; } /// /// (default 0.5`), [0..1] /// public float RandomizationFactor { get { return randomizationFactor; } set { randomizationFactor = Math.Min(1.0f, Math.Max(0.0f, value)); } } private float randomizationFactor; /// /// Connection timeout before a connect_error and connect_timeout events are emitted (default 20000ms) /// public TimeSpan Timeout { get; set; } /// /// By setting this false, you have to call SocketManager's Open() whenever you decide it's appropriate. /// public bool AutoConnect { get; set; } /// /// Additional query parameters that will be passed for accessed uris. If the value is null, or an empty string it will be not appended to the query only the key. /// The keys and values must be escaped properly, as the plugin will not escape these. /// public ObservableDictionary AdditionalQueryParams { get { return additionalQueryParams; } set { // Unsubscribe from previous dictionary's events if (additionalQueryParams != null) additionalQueryParams.CollectionChanged -= AdditionalQueryParams_CollectionChanged; additionalQueryParams = value; // Clear out the cached value BuiltQueryParams = null; // Subscribe to the collection changed event if (value != null) value.CollectionChanged += AdditionalQueryParams_CollectionChanged; } } private ObservableDictionary additionalQueryParams; /// /// If it's false, the parameters in the AdditionalQueryParams will be passed for all HTTP requests. Its default value is true. /// public bool QueryParamsOnlyForHandshake { get; set; } /// /// A callback that called for every HTTPRequest the socket.io protocol sends out. It can be used to further customize (add additional request for example) requests. /// public HTTPRequestCallbackDelegate HTTPRequestCustomizationCallback { get; set; } /// /// Socket.IO protocol version of the server. If left as default (Unknown) the plugin tries to detect the server version. /// public SupportedSocketIOVersions ServerVersion { get; set; } /// /// Starting with Socket.IO v3, connecting to a namespace a client can send payload data. When the Auth callback function is set, the plugin going to call it when connecting to a namespace. Its return value must be a json string! /// public Func Auth; #endregion /// /// The cached value of the result of the BuildQueryParams() call. /// private string BuiltQueryParams; /// /// Constructor, setting the default option values. /// public SocketOptions() { ConnectWith = Transports.TransportTypes.Polling; Reconnection = true; ReconnectionAttempts = int.MaxValue; ReconnectionDelay = TimeSpan.FromMilliseconds(1000); ReconnectionDelayMax = TimeSpan.FromMilliseconds(5000); RandomizationFactor = 0.5f; Timeout = TimeSpan.FromMilliseconds(20000); AutoConnect = true; QueryParamsOnlyForHandshake = true; } #region Helper Functions /// /// Builds the keys and values from the AdditionalQueryParams to an key=value form. If AdditionalQueryParams is null or empty, it will return an empty string. /// internal string BuildQueryParams() { if (AdditionalQueryParams == null || AdditionalQueryParams.Count == 0) return string.Empty; if (!string.IsNullOrEmpty(BuiltQueryParams)) return BuiltQueryParams; StringBuilder sb = new StringBuilder(AdditionalQueryParams.Count * 4); foreach(var kvp in AdditionalQueryParams) { sb.Append("&"); sb.Append(kvp.Key); if (!string.IsNullOrEmpty(kvp.Value)) { sb.Append("="); sb.Append(kvp.Value); } } return BuiltQueryParams = sb.ToString(); } /// /// This event will be called when the AdditonalQueryPrams dictionary changed. We have to reset the cached values. /// private void AdditionalQueryParams_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { BuiltQueryParams = null; } #endregion } } #endif