private void StartSubscription(PubnubSubscription subscription) { Task.Factory.StartNew(() => { int failureCount = 0; // check if the subscription still exists in the dictionary // if not, then end this task, otherwise, repeat. using (var handle = new System.Threading.ManualResetEventSlim(false)) { while (_subscriptions.ContainsKey(subscription.Channel)) { try { var url = PubnubRequest.BuildUrl(PubnubConfiguration.EnableSsl, "subscribe", PubnubConfiguration.SubscribeKey, subscription.Channel, "0", subscription.TimeToken.ToString(CultureInfo.InvariantCulture)); var request = new PubnubRequest(); string json; request.Execute(url, out json); var result = JsonConvert.DeserializeObject<List<object>>(json); #if DEBUG System.Diagnostics.Debug.WriteLine(json); #endif if (result[0] is JArray && result[0].ToString() != "[]") { // loop through each message and fire individually for (var i = 0; i < ((JArray)result[0]).Count; i++) { var message = ((JArray)result[0])[i].ToString(); if (MessageRecieved != null && !string.IsNullOrEmpty(message)) try { MessageRecieved(null, new PubNubEventArgs { Channel = subscription.Channel, Message = message }); } catch (Exception exp) { // adding this try catch because if we have multiple messages and one of // them encouters an unhandled exception it should not impact the others // or the subscription time token. System.Diagnostics.Debug.WriteLine("MessageRecievedException: " + exp.Message); } } } // update the time token PubnubSubscription retrievedSubscription; if (_subscriptions.TryGetValue(subscription.Channel, out retrievedSubscription)) retrievedSubscription.TimeToken = Convert.ToInt64(result[1].ToString()); // reset the failure count failureCount = 0; } catch (Exception exp) { System.Diagnostics.Debug.WriteLine("SubscriptionException: " + exp.Message); failureCount++; handle.Wait(GetWaitTimeForErrorCount(failureCount)); // rather than throwing the errors, we collect them for // periodic analysis, the idea is to enhance this with error limits // and a backoff strategy incase there is a problem with Pubnub // or the local connection to pubnub PubnubSubscription retrievedSubscription; if (_subscriptions.TryGetValue(subscription.Channel, out retrievedSubscription)) retrievedSubscription.Errors.Add(exp); } } } }); }
/// <summary> /// Starts a looping subscription request which runs on it's own /// thread. /// </summary> /// <param name="channel"></param> /// <returns></returns> public bool Subscribe(string channel) { var subscription = new PubnubSubscription { Channel = channel, TimeToken = 0 }; // Add a new one if (!_subscriptions.TryAdd(channel, subscription)) return false; //Subscription already exists StartSubscription(subscription); return true; }