PageRenderTime 110ms CodeModel.GetById 68ms RepoModel.GetById 0ms app.codeStats 1ms

/mono-for-mac/3.3.0.1/PubNub-Messaging/PubNub-Console/Pubnub.cs

https://github.com/jhey/pubnub-api
C# | 3012 lines | 2303 code | 326 blank | 383 comment | 428 complexity | 7022754966b3d718fe93683ccb682920 MD5 | raw file
Possible License(s): Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. //Build Date: Dec 06, 2012
  2. #if (__MonoCS__)
  3. #define TRACE
  4. #endif
  5. using System;
  6. using System.IO;
  7. using System.Text;
  8. using System.Net;
  9. using System.Collections;
  10. using System.Collections.Generic;
  11. using System.Security.Cryptography;
  12. using System.ComponentModel;
  13. using System.Reflection;
  14. using System.Threading;
  15. using System.Diagnostics;
  16. using System.Collections.Concurrent;
  17. using System.Net.NetworkInformation;
  18. using System.Net.Sockets;
  19. using System.Configuration;
  20. using Microsoft.Win32;
  21. #if (SILVERLIGHT)
  22. using TvdP.Collections;
  23. #endif
  24. using System.Linq;
  25. using Newtonsoft.Json;
  26. using Newtonsoft.Json.Linq;
  27. #if (SILVERLIGHT || WINDOWS_PHONE)
  28. using System.Windows.Threading;
  29. using System.IO.IsolatedStorage;
  30. #endif
  31. namespace PubNub_Messaging
  32. {
  33. // INotifyPropertyChanged provides a standard event for objects to notify clients that one of its properties has changed
  34. public class Pubnub : INotifyPropertyChanged
  35. {
  36. const int PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC = 310;
  37. const int PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC = 15;
  38. const int PUBNUB_NETWORK_CHECK_RETRIES = 50;
  39. const int PUBNUB_WEBREQUEST_RETRY_INTERVAL_IN_SEC = 10;
  40. const bool OVERRIDE_TCP_KEEP_ALIVE = true;
  41. const TraceLevel CAPTURE_TRACE_LEVEL = TraceLevel.Info;
  42. // Common property changed event
  43. public event PropertyChangedEventHandler PropertyChanged;
  44. public void RaisePropertyChanged(string propertyName)
  45. {
  46. var handler = PropertyChanged;
  47. if (handler != null)
  48. {
  49. handler(this, new PropertyChangedEventArgs(propertyName));
  50. }
  51. }
  52. ConcurrentDictionary<string, long> _channelSubscription = new ConcurrentDictionary<string, long>();
  53. ConcurrentDictionary<string, long> _channelPresence = new ConcurrentDictionary<string, long>();
  54. ConcurrentDictionary<string, RequestState> _channelRequest = new ConcurrentDictionary<string, RequestState>();
  55. ConcurrentDictionary<string, bool> _channelInternetStatus = new ConcurrentDictionary<string, bool>();
  56. ConcurrentDictionary<string, int> _channelInternetRetry = new ConcurrentDictionary<string, int>();
  57. ConcurrentDictionary<string, Timer> _channelReconnectTimer = new ConcurrentDictionary<string, Timer>();
  58. System.Threading.Timer heartBeatTimer;
  59. private static bool _pubnetSystemActive = true;
  60. // Publish
  61. private ConcurrentDictionary<string, object> _publishMsg = new ConcurrentDictionary<string, object>();
  62. // History of Messages
  63. private List<object> _History = new List<object>();
  64. public List<object> History { get { return _History; } set { _History = value; RaisePropertyChanged("History"); } }
  65. // Subscribe
  66. private ConcurrentDictionary<string, object> _subscribeMsg = new ConcurrentDictionary<string, object>();
  67. // Presence
  68. private ConcurrentDictionary<string, object> _presenceMsg = new ConcurrentDictionary<string, object>();
  69. // Timestamp
  70. private List<object> _Time = new List<object>();
  71. // Pubnub Core API implementation
  72. private string ORIGIN = "pubsub.pubnub.com";
  73. private string PUBLISH_KEY = "";
  74. private string SUBSCRIBE_KEY = "";
  75. private string SECRET_KEY = "";
  76. private string CIPHER_KEY = "";
  77. private bool SSL = false;
  78. private string sessionUUID = "";
  79. private string parameters = "";
  80. /**
  81. * Pubnub instance initialization function
  82. *
  83. * @param string pubish_key.
  84. * @param string subscribe_key.
  85. * @param string secret_key.
  86. * @param bool ssl_on
  87. */
  88. private void init(string publish_key, string subscribe_key, string secret_key, string cipher_key, bool ssl_on)
  89. {
  90. this.PUBLISH_KEY = publish_key;
  91. this.SUBSCRIBE_KEY = subscribe_key;
  92. this.SECRET_KEY = secret_key;
  93. this.CIPHER_KEY = cipher_key;
  94. this.SSL = ssl_on;
  95. if (this.sessionUUID == "")
  96. this.sessionUUID = Guid.NewGuid().ToString();
  97. // SSL is ON?
  98. if (this.SSL)
  99. this.ORIGIN = "https://" + this.ORIGIN;
  100. else
  101. this.ORIGIN = "http://" + this.ORIGIN;
  102. //Initiate System Events for PowerModeChanged - to monitor suspend/resume
  103. initiatePowerModeCheck();
  104. }
  105. private void reconnectNetwork<T>(ReconnectState<T> netState)
  106. {
  107. System.Threading.Timer timer = new Timer(new TimerCallback(reconnectNetworkCallback<T>), netState, 0, PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  108. _channelReconnectTimer.AddOrUpdate(netState.channel, timer, (key, oldState) => timer);
  109. }
  110. void reconnectNetworkCallback<T>(Object reconnectState)
  111. {
  112. try
  113. {
  114. ReconnectState<T> netState = reconnectState as ReconnectState<T>;
  115. if (netState != null)
  116. {
  117. if (_channelInternetStatus.ContainsKey(netState.channel)
  118. && (netState.type == ResponseType.Subscribe || netState.type == ResponseType.Presence))
  119. {
  120. if (_channelInternetStatus[netState.channel])
  121. {
  122. //Reset Retry if previous state is true
  123. _channelInternetRetry.AddOrUpdate(netState.channel, 0, (key, oldValue) => 0);
  124. }
  125. else
  126. {
  127. _channelInternetRetry.AddOrUpdate(netState.channel, 1, (key, oldValue) => oldValue + 1);
  128. WriteToLog(string.Format("DateTime {0}, {1} {2} reconnectNetworkCallback. Retry {3} of {4}", DateTime.Now.ToString(), netState.channel, netState.type, _channelInternetRetry[netState.channel], PUBNUB_NETWORK_CHECK_RETRIES), TraceLevel.Info);
  129. }
  130. }
  131. if (_channelInternetStatus[netState.channel])
  132. {
  133. if (_channelReconnectTimer.ContainsKey(netState.channel))
  134. {
  135. _channelReconnectTimer[netState.channel].Change(Timeout.Infinite, Timeout.Infinite);
  136. _channelReconnectTimer[netState.channel].Dispose();
  137. }
  138. WriteToLog(string.Format("DateTime {0}, {1} {2} reconnectNetworkCallback. Internet Available : {3}", DateTime.Now.ToString(), netState.channel, netState.type, _channelInternetStatus[netState.channel]), TraceLevel.Info);
  139. switch (netState.type)
  140. {
  141. case ResponseType.Subscribe:
  142. _subscribe(netState.channel, netState.timetoken, netState.callback, false);
  143. break;
  144. case ResponseType.Presence:
  145. _presence(netState.channel, netState.timetoken, netState.callback, false);
  146. break;
  147. default:
  148. break;
  149. }
  150. }
  151. else if (_channelInternetRetry[netState.channel] >= PUBNUB_NETWORK_CHECK_RETRIES)
  152. {
  153. if (_channelReconnectTimer.ContainsKey(netState.channel))
  154. {
  155. _channelReconnectTimer[netState.channel].Change(Timeout.Infinite, Timeout.Infinite);
  156. _channelReconnectTimer[netState.channel].Dispose();
  157. }
  158. switch (netState.type)
  159. {
  160. case ResponseType.Subscribe:
  161. subscribeExceptionHandler(netState.channel, netState.callback, true);
  162. break;
  163. case ResponseType.Presence:
  164. presenceExceptionHandler(netState.channel, netState.callback, true);
  165. break;
  166. default:
  167. break;
  168. }
  169. }
  170. }
  171. else
  172. {
  173. WriteToLog(string.Format("DateTime {0}, Unknown request state in reconnectNetworkCallback", DateTime.Now.ToString()), TraceLevel.Error);
  174. }
  175. }
  176. catch (Exception ex)
  177. {
  178. WriteToLog(string.Format("DateTime {0} method:reconnectNetworkCallback \n Exception Details={1}", DateTime.Now.ToString(), ex.ToString()), TraceLevel.Error);
  179. }
  180. }
  181. private void initiatePowerModeCheck()
  182. {
  183. #if (!SILVERLIGHT && !WINDOWS_PHONE)
  184. try
  185. {
  186. SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
  187. WriteToLog(string.Format("DateTime {0}, Initiated System Event - PowerModeChanged.", DateTime.Now.ToString()), TraceLevel.Info);
  188. }
  189. catch (Exception ex)
  190. {
  191. WriteToLog(string.Format("DateTime {0} No support for System Event - PowerModeChanged.", DateTime.Now.ToString()), TraceLevel.Error);
  192. WriteToLog(string.Format("DateTime {0} {1}", DateTime.Now.ToString(), ex.ToString()), TraceLevel.Error);
  193. }
  194. #endif
  195. }
  196. #if (!SILVERLIGHT && !WINDOWS_PHONE)
  197. void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
  198. {
  199. if (e.Mode == PowerModes.Suspend)
  200. {
  201. _pubnetSystemActive = false;
  202. TerminatePendingWebRequest();
  203. if (OVERRIDE_TCP_KEEP_ALIVE)
  204. {
  205. heartBeatTimer.Change(Timeout.Infinite, Timeout.Infinite);
  206. }
  207. WriteToLog(string.Format("DateTime {0}, System entered into Suspend Mode.", DateTime.Now.ToString()), TraceLevel.Info);
  208. if (OVERRIDE_TCP_KEEP_ALIVE)
  209. {
  210. WriteToLog(string.Format("DateTime {0}, Disabled Timer for heartbeat ", DateTime.Now.ToString()), TraceLevel.Info);
  211. }
  212. }
  213. else if (e.Mode == PowerModes.Resume)
  214. {
  215. _pubnetSystemActive = true;
  216. if (OVERRIDE_TCP_KEEP_ALIVE)
  217. {
  218. heartBeatTimer.Change(
  219. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000,
  220. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  221. }
  222. WriteToLog(string.Format("DateTime {0}, System entered into Resume/Awake Mode.", DateTime.Now.ToString()), TraceLevel.Info);
  223. if (OVERRIDE_TCP_KEEP_ALIVE)
  224. {
  225. WriteToLog(string.Format("DateTime {0}, Enabled Timer for heartbeat ", DateTime.Now.ToString()), TraceLevel.Info);
  226. }
  227. }
  228. }
  229. #endif
  230. private void TerminatePendingWebRequest()
  231. {
  232. TerminatePendingWebRequest(null);
  233. }
  234. private void TerminatePendingWebRequest(RequestState state)
  235. {
  236. if (state != null && state.request != null)
  237. {
  238. state.request.Abort();
  239. WriteToLog(string.Format("DateTime {0} TerminatePendingWebRequest {1}", DateTime.Now.ToString(), state.request.RequestUri.ToString()), TraceLevel.Info);
  240. RequestState removedReq;
  241. bool removeKey = _channelRequest.TryRemove(state.channel, out removedReq);
  242. if (!removeKey)
  243. {
  244. WriteToLog(string.Format("DateTime {0} Unable to remove web request from dictionary in TerminatePendingWebRequest for channel= {1}", DateTime.Now.ToString(), state.channel), TraceLevel.Error);
  245. }
  246. }
  247. else
  248. {
  249. ConcurrentDictionary<string, RequestState> webReq = _channelRequest;
  250. ICollection<string> keyCol = _channelRequest.Keys;
  251. foreach (string key in keyCol)
  252. {
  253. RequestState currReq = _channelRequest[key];
  254. if (currReq.request != null)
  255. {
  256. currReq.request.Abort();
  257. WriteToLog(string.Format("DateTime {0} TerminatePendingWebRequest {1}", DateTime.Now.ToString(), currReq.request.RequestUri.ToString()), TraceLevel.Info);
  258. bool removeKey = _channelRequest.TryRemove(key, out currReq);
  259. if (!removeKey)
  260. {
  261. WriteToLog(string.Format("DateTime {0} Unable to remove web request from dictionary in TerminatePendingWebRequest for channel= {1}", DateTime.Now.ToString(), key), TraceLevel.Error);
  262. }
  263. }
  264. }
  265. }
  266. }
  267. #if (!SILVERLIGHT && !WINDOWS_PHONE)
  268. ~Pubnub()
  269. {
  270. //detach
  271. SystemEvents.PowerModeChanged -= new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
  272. }
  273. #endif
  274. /**
  275. * PubNub 3.0 API
  276. *
  277. * Prepare Pubnub messaging class initial state
  278. *
  279. * @param string pubish_key.
  280. * @param string subscribe_key.
  281. * @param string secret_key.
  282. * @param bool ssl_on
  283. */
  284. public Pubnub(string publish_key, string subscribe_key, string secret_key, string cipher_key, bool ssl_on)
  285. {
  286. this.init(publish_key, subscribe_key, secret_key, cipher_key, ssl_on);
  287. }
  288. /**
  289. * PubNub 2.0 Compatibility
  290. *
  291. * Prepare Pubnub messaging class initial state
  292. *
  293. * @param string pubish_key.
  294. * @param string subscribe_key.
  295. */
  296. public Pubnub(string publish_key, string subscribe_key)
  297. {
  298. this.init(publish_key, subscribe_key, "", "", false);
  299. }
  300. /**
  301. * PubNub 3.0 without SSL
  302. *
  303. * Prepare Pubnub messaging class initial state
  304. *
  305. * @param string pubish_key.
  306. * @param string subscribe_key.
  307. * @param string secret_key.
  308. */
  309. public Pubnub(string publish_key, string subscribe_key, string secret_key)
  310. {
  311. this.init(publish_key, subscribe_key, secret_key, "", false);
  312. }
  313. /**
  314. * History
  315. *
  316. * Load history from a channel
  317. *
  318. * @param String channel name.
  319. * @param int limit history count response
  320. * @return ListArray of history
  321. */
  322. [Obsolete("This method should no longer be used, please use detailedHistory() instead.")]
  323. public bool history(string channel, int limit)
  324. {
  325. List<string> url = new List<string>();
  326. url.Add("history");
  327. url.Add(this.SUBSCRIBE_KEY);
  328. url.Add(channel);
  329. url.Add("0");
  330. url.Add(limit.ToString());
  331. return _request(url, ResponseType.History);
  332. }
  333. /**
  334. * Detailed History
  335. */
  336. public bool detailedHistory(string channel, long start, long end, int count, bool reverse, Action<object> usercallback)
  337. {
  338. return detailedHistory<object>(channel, start, end, count, reverse, usercallback);
  339. }
  340. public bool detailedHistory<T>(string channel, long start, long end, int count, bool reverse, Action<T> usercallback)
  341. {
  342. if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()))
  343. {
  344. throw new ArgumentException("Missing Channel");
  345. }
  346. Uri request = buildDetailedHistoryRequest(channel, start, end, count, reverse);
  347. return _urlRequest<T>(request, channel, ResponseType.DetailedHistory, usercallback, false);
  348. }
  349. public bool detailedHistory(string channel, long start, Action<object> usercallback, bool reverse)
  350. {
  351. return detailedHistory<object>(channel, start, -1, -1, reverse, usercallback);
  352. }
  353. public bool detailedHistory<T>(string channel, long start, Action<T> usercallback, bool reverse)
  354. {
  355. return detailedHistory<T>(channel, start, -1, -1, reverse, usercallback);
  356. }
  357. public bool detailedHistory(string channel, int count, Action<object> usercallback)
  358. {
  359. return detailedHistory<object>(channel, -1, -1, count, false, usercallback);
  360. }
  361. public bool detailedHistory<T>(string channel, int count, Action<T> usercallback)
  362. {
  363. return detailedHistory<T>(channel, -1, -1, count, false, usercallback);
  364. }
  365. /**
  366. * Publish
  367. *
  368. * Send a message to a channel
  369. *
  370. * @param String channel name.
  371. * @param List<object> info.
  372. * @return bool false on fail
  373. */
  374. public bool publish(string channel, object message, Action<object> usercallback)
  375. {
  376. return publish<object>(channel, message, usercallback);
  377. }
  378. public bool publish<T>(string channel, object message, Action<T> usercallback)
  379. {
  380. if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()) || message == null)
  381. {
  382. throw new ArgumentException("Missing Channel or Message");
  383. }
  384. if (string.IsNullOrEmpty(this.PUBLISH_KEY) || string.IsNullOrEmpty(this.PUBLISH_KEY.Trim()) || this.PUBLISH_KEY.Length <= 0)
  385. {
  386. throw new MissingFieldException("Invalid publish key");
  387. }
  388. if (usercallback == null)
  389. {
  390. throw new ArgumentException("Missing Callback");
  391. }
  392. Uri request = buildPublishRequest(channel, message);
  393. return _urlRequest<T>(request, channel, ResponseType.Publish, usercallback, false);
  394. }
  395. private string jsonEncodePublishMsg(object originalMsg)
  396. {
  397. string msg = SerializeToJsonString(originalMsg);
  398. if (this.CIPHER_KEY.Length > 0)
  399. {
  400. PubnubCrypto aes = new PubnubCrypto(this.CIPHER_KEY);
  401. string encryptMsg = aes.encrypt(msg);
  402. msg = SerializeToJsonString(encryptMsg);
  403. }
  404. return msg;
  405. }
  406. private List<object> decodeMsg(List<object> message, ResponseType type)
  407. {
  408. List<object> receivedMsg = new List<object>();
  409. if (type == ResponseType.Presence || type == ResponseType.Publish || type == ResponseType.Time || type == ResponseType.Here_Now || type == ResponseType.Leave)
  410. {
  411. return message;
  412. }
  413. else if (type == ResponseType.DetailedHistory)
  414. {
  415. receivedMsg = decodeDecryptLoop(message);
  416. }
  417. else
  418. {
  419. receivedMsg = decodeDecryptLoop(message);
  420. }
  421. return receivedMsg;
  422. }
  423. private List<object> decodeDecryptLoop(List<object> message)
  424. {
  425. List<object> returnMsg = new List<object>();
  426. if (this.CIPHER_KEY.Length > 0)
  427. {
  428. PubnubCrypto aes = new PubnubCrypto(this.CIPHER_KEY);
  429. var myObjectArray = (from item in message select item as object).ToArray();
  430. IEnumerable enumerable = myObjectArray[0] as IEnumerable;
  431. if (enumerable != null)
  432. {
  433. List<object> receivedMsg = new List<object>();
  434. foreach (object element in enumerable)
  435. {
  436. string decryptMsg = aes.decrypt(element.ToString());
  437. object decodeMsg = (decryptMsg == "**DECRYPT ERROR**") ? decryptMsg : JsonConvert.DeserializeObject<object>(decryptMsg);
  438. receivedMsg.Add(decodeMsg);
  439. }
  440. returnMsg.Add(receivedMsg);
  441. }
  442. for (int index = 1; index < myObjectArray.Length; index++)
  443. {
  444. returnMsg.Add(myObjectArray[index]);
  445. }
  446. return returnMsg;
  447. }
  448. else
  449. {
  450. var myObjectArray = (from item in message select item as object).ToArray();
  451. IEnumerable enumerable = myObjectArray[0] as IEnumerable;
  452. if (enumerable != null)
  453. {
  454. List<object> receivedMsg = new List<object>();
  455. foreach (object element in enumerable)
  456. {
  457. receivedMsg.Add(element);
  458. }
  459. returnMsg.Add(receivedMsg);
  460. }
  461. for (int index = 1; index < myObjectArray.Length; index++)
  462. {
  463. returnMsg.Add(myObjectArray[index]);
  464. }
  465. return returnMsg;
  466. }
  467. }
  468. /**
  469. * Subscribe
  470. *
  471. * Listen for a message on a channel (BLOCKING)
  472. *
  473. * @param String channel name.
  474. * @param Procedure function callback
  475. */
  476. public void subscribe(string channel, Action<object> usercallback)
  477. {
  478. subscribe<object>(channel, usercallback);
  479. }
  480. public void subscribe<T>(string channel, Action<T> usercallback)
  481. {
  482. if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()))
  483. {
  484. throw new ArgumentException("Missing Channel");
  485. }
  486. if (usercallback == null)
  487. {
  488. throw new ArgumentException("Missing Callback");
  489. }
  490. WriteToLog(string.Format("DateTime {0}, requested subscribe for channel={1}", DateTime.Now.ToString(), channel), TraceLevel.Info);
  491. if (_channelSubscription.ContainsKey(channel))
  492. {
  493. List<object> result = new List<object>();
  494. string jsonString = "[0, \"Already subscribed\"]";
  495. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  496. result.Add(channel);
  497. WriteToLog(string.Format("DateTime {0}, JSON subscribe response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  498. goToUserCallback<T>(result, usercallback);
  499. }
  500. else
  501. {
  502. _channelSubscription.GetOrAdd(channel, 0);
  503. resetInternetCheckSettings(channel);
  504. _subscribe<T>(channel, 0, usercallback, false);
  505. }
  506. }
  507. private void resetInternetCheckSettings(string channel)
  508. {
  509. if (_channelInternetStatus.ContainsKey(channel))
  510. {
  511. _channelInternetStatus.AddOrUpdate(channel, true, (key, oldValue) => true);
  512. }
  513. else
  514. {
  515. _channelInternetStatus.GetOrAdd(channel, true); //Set to true for internet connection
  516. }
  517. if (_channelInternetRetry.ContainsKey(channel))
  518. {
  519. _channelInternetRetry.AddOrUpdate(channel, 0, (key, oldValue) => 0);
  520. }
  521. else
  522. {
  523. _channelInternetRetry.GetOrAdd(channel, 0); //Initialize the internet retry count
  524. }
  525. }
  526. void OnPubnubWebRequestTimeout(object state, bool timeout)
  527. {
  528. if (timeout)
  529. {
  530. RequestState currentState = state as RequestState;
  531. if (currentState != null)
  532. {
  533. HttpWebRequest request = currentState.request;
  534. if (request != null)
  535. {
  536. WriteToLog(string.Format("DateTime: {0}, OnPubnubWebRequestTimeout: client request timeout reached.Request aborted for channel = {1}", DateTime.Now.ToString(), currentState.channel), TraceLevel.Info);
  537. request.Abort();
  538. }
  539. }
  540. else
  541. {
  542. WriteToLog(string.Format("DateTime: {0}, OnPubnubWebRequestTimeout: client request timeout reached. However state is unknown", DateTime.Now.ToString()), TraceLevel.Error);
  543. }
  544. if (OVERRIDE_TCP_KEEP_ALIVE)
  545. {
  546. //reset heart beat time because http request already timedout
  547. heartBeatTimer.Change(
  548. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000,
  549. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  550. WriteToLog(string.Format("DateTime: {0}, OnPubnubWebRequestTimeout: resetting the heartbeat timeout", DateTime.Now.ToString()), TraceLevel.Info);
  551. }
  552. }
  553. }
  554. void OnPubnubHeartBeatTimeoutCallback(Object heartbeatState)
  555. {
  556. WriteToLog(string.Format("DateTime: {0}, **OnPubnubHeartBeatTimeoutCallback**", DateTime.Now.ToString()), TraceLevel.Verbose);
  557. RequestState currentState = heartbeatState as RequestState;
  558. if (currentState != null)
  559. {
  560. bool networkConnection = ClientNetworkStatus.checkInternetStatus(_pubnetSystemActive);
  561. if (_channelInternetStatus.ContainsKey(currentState.channel)
  562. && (currentState.type == ResponseType.Subscribe || currentState.type == ResponseType.Presence)
  563. && OVERRIDE_TCP_KEEP_ALIVE)
  564. {
  565. _channelInternetStatus[currentState.channel] = networkConnection;
  566. WriteToLog(string.Format("DateTime: {0}, OnPubnubHeartBeatTimeoutCallback - Internet connection = {1}", DateTime.Now.ToString(), networkConnection), TraceLevel.Verbose);
  567. if (!networkConnection)
  568. {
  569. TerminatePendingWebRequest(currentState);
  570. }
  571. }
  572. }
  573. }
  574. /// <summary>
  575. /// Check the response of the REST API and call for re-subscribe
  576. /// </summary>
  577. /// <typeparam name="T"></typeparam>
  578. /// <param name="subscribeResult"></param>
  579. /// <param name="usercallback"></param>
  580. private void subscribeInternalCallback<T>(object subscribeResult, Action<T> usercallback)
  581. {
  582. List<object> message = subscribeResult as List<object>;
  583. string channelName = "";
  584. if (message != null && message.Count >= 3)
  585. {
  586. channelName = message[2].ToString();
  587. }
  588. else
  589. {
  590. WriteToLog(string.Format("DateTime {0}, Lost Channel Name for resubscribe", DateTime.Now.ToString()), TraceLevel.Error);
  591. return;
  592. }
  593. if (!_channelSubscription.ContainsKey(channelName))
  594. {
  595. WriteToLog(string.Format("DateTime {0}, Due to Unsubscribe, further re-subscription was stopped for channel {1}", DateTime.Now.ToString(), channelName.ToString()), TraceLevel.Info);
  596. return;
  597. }
  598. if (message != null && message.Count >= 3)
  599. {
  600. _subscribe<T>(channelName, (object)message[1], usercallback, false);
  601. }
  602. }
  603. private void presenceInternalCallback<T>(object presenceResult, Action<T> usercallback)
  604. {
  605. List<object> message = presenceResult as List<object>;
  606. string channelName = "";
  607. if (message != null && message.Count >= 3)
  608. {
  609. channelName = message[2].ToString();
  610. }
  611. else
  612. {
  613. WriteToLog(string.Format("DateTime {0}, Lost Channel Name for re-presence", DateTime.Now.ToString()), TraceLevel.Error);
  614. return;
  615. }
  616. if (message != null && message.Count >= 3)
  617. {
  618. _presence<T>(channelName, (object)message[1], usercallback, false);
  619. }
  620. }
  621. /// <summary>
  622. /// To unsubscribe a channel
  623. /// </summary>
  624. /// <param name="channel"></param>
  625. /// <param name="usercallback"></param>
  626. public void unsubscribe(string channel, Action<object> usercallback)
  627. {
  628. unsubscribe<object>(channel, usercallback);
  629. }
  630. /// <summary>
  631. /// To unsubscribe a channel
  632. /// </summary>
  633. /// <typeparam name="T"></typeparam>
  634. /// <param name="channel"></param>
  635. /// <param name="usercallback"></param>
  636. public void unsubscribe<T>(string channel, Action<T> usercallback)
  637. {
  638. if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()))
  639. {
  640. throw new ArgumentException("Missing Channel");
  641. }
  642. bool unsubStatus = false;
  643. WriteToLog(string.Format("DateTime {0}, requested unsubscribe for channel={1}", DateTime.Now.ToString(), channel), TraceLevel.Info);
  644. string jsonString = "";
  645. List<object> result = new List<object>();
  646. if (_channelSubscription.ContainsKey(channel))
  647. {
  648. long unsubValue;
  649. unsubStatus = _channelSubscription.TryRemove(channel, out unsubValue);
  650. if (unsubStatus)
  651. {
  652. if (_channelRequest.ContainsKey(channel))
  653. {
  654. HttpWebRequest storedRequest = _channelRequest[channel].request;
  655. storedRequest.Abort();
  656. }
  657. jsonString = string.Format("[1, \"Unsubscribed from {0}\"]", channel);
  658. }
  659. else
  660. {
  661. jsonString = string.Format("[1, \"Error unsubscribing from {0}\"]", channel);
  662. }
  663. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  664. result.Add(channel);
  665. WriteToLog(string.Format("DateTime {0}, JSON unsubscribe response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  666. goToUserCallback<T>(result, usercallback);
  667. //just fire leave() event to REST API for safeguard
  668. Uri request = buildLeaveRequest(channel);
  669. _urlRequest<T>(request, channel, ResponseType.Leave, null, false);
  670. }
  671. else
  672. {
  673. result = new List<object>();
  674. jsonString = "[0, \"Channel Not Subscribed\"]";
  675. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  676. result.Add(channel);
  677. WriteToLog(string.Format("DateTime {0}, JSON unsubscribe response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  678. goToUserCallback<T>(result, usercallback);
  679. }
  680. }
  681. /**
  682. * Subscribe - Private Interface
  683. *
  684. * @param String channel name.
  685. * @param Procedure function callback
  686. * @param String timetoken.
  687. */
  688. private void _subscribe<T>(string channel, object timetoken, Action<T> usercallback, bool reconnect)
  689. {
  690. //Exit if the channel is unsubscribed
  691. if (!_channelSubscription.ContainsKey(channel))
  692. {
  693. WriteToLog(string.Format("DateTime {0}, Due to Unsubscribe, further subscription was stopped for channel {1}", DateTime.Now.ToString(), channel.ToString()), TraceLevel.Info);
  694. return;
  695. }
  696. _channelSubscription.AddOrUpdate(channel, Convert.ToInt64(timetoken.ToString()), (key, oldValue) => Convert.ToInt64(timetoken.ToString())); //Store the timetoken
  697. if (_channelInternetStatus.ContainsKey(channel) && (!_channelInternetStatus[channel]) && _pubnetSystemActive)
  698. {
  699. if (_channelInternetRetry.ContainsKey(channel) && (_channelInternetRetry[channel] >= PUBNUB_NETWORK_CHECK_RETRIES))
  700. {
  701. WriteToLog(string.Format("DateTime {0}, Subscribe channel={1} - No internet connection. MAXed retries for internet ", DateTime.Now.ToString(), channel), TraceLevel.Info);
  702. subscribeExceptionHandler<T>(channel, usercallback, true);
  703. return;
  704. }
  705. if (OVERRIDE_TCP_KEEP_ALIVE)
  706. {
  707. WriteToLog(string.Format("DateTime {0}, Subscribe - No internet connection for {1}", DateTime.Now.ToString(), channel), TraceLevel.Info);
  708. ReconnectState<T> netState = new ReconnectState<T>();
  709. netState.channel = channel;
  710. netState.type = ResponseType.Subscribe;
  711. netState.callback = usercallback;
  712. netState.timetoken = timetoken;
  713. reconnectNetwork<T>(netState);
  714. return;
  715. }
  716. }
  717. // Begin recursive subscribe
  718. try
  719. {
  720. // Build URL
  721. Uri request = buildSubscribeRequest(channel, timetoken);
  722. // Wait for message
  723. _urlRequest<T>(request, channel, ResponseType.Subscribe, usercallback, reconnect);
  724. }
  725. catch (Exception ex)
  726. {
  727. WriteToLog(string.Format("DateTime {0} method:_subscribe \n channel={1} \n timetoken={2} \n Exception Details={3}", DateTime.Now.ToString(), channel, timetoken.ToString(), ex.ToString()), TraceLevel.Error);
  728. this._subscribe<T>(channel, timetoken, usercallback, false);
  729. }
  730. }
  731. /**
  732. * Presence feature
  733. *
  734. * Listen for a presence message on a channel (BLOCKING)
  735. *
  736. * @param String channel name. (+"pnpres")
  737. * @param Procedure function callback
  738. */
  739. public void presence(string channel, Action<object> usercallback)
  740. {
  741. presence<object>(channel, usercallback);
  742. }
  743. public void presence<T>(string channel, Action<T> usercallback)
  744. {
  745. if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()))
  746. {
  747. throw new ArgumentException("Missing Channel");
  748. }
  749. if (usercallback == null)
  750. {
  751. throw new ArgumentException("Missing Callback");
  752. }
  753. channel = string.Format("{0}-pnpres", channel);
  754. WriteToLog(string.Format("DateTime {0}, requested presence for channel={1}", DateTime.Now.ToString(), channel), TraceLevel.Info);
  755. if (_channelPresence.ContainsKey(channel))
  756. {
  757. List<object> result = new List<object>();
  758. string jsonString = "[0, \"Presence Already subscribed\"]";
  759. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  760. result.Add(channel.Replace("-pnpres", ""));
  761. WriteToLog(string.Format("DateTime {0}, JSON presence response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  762. goToUserCallback<T>(result, usercallback);
  763. }
  764. else
  765. {
  766. _channelPresence.GetOrAdd(channel, 0);
  767. resetInternetCheckSettings(channel);
  768. this._presence<T>(channel, 0, usercallback, false);
  769. }
  770. }
  771. /**
  772. * Presence feature - Private Interface
  773. *
  774. * @param String channel name.
  775. * @param Procedure function callback
  776. * @param String timetoken.
  777. */
  778. private void _presence<T>(string channel, object timetoken, Action<T> usercallback, bool reconnect)
  779. {
  780. //Exit if the channel is unsubscribed
  781. if (!_channelPresence.ContainsKey(channel))
  782. {
  783. WriteToLog(string.Format("DateTime {0}, Due to Presence-unsubscribe, further presence was stopped for channel {1}", DateTime.Now.ToString(), channel.ToString()), TraceLevel.Info);
  784. return;
  785. }
  786. _channelPresence.AddOrUpdate(channel, Convert.ToInt64(timetoken.ToString()), (key, oldValue) => Convert.ToInt64(timetoken.ToString())); //Store the timetoken
  787. if (_channelInternetStatus.ContainsKey(channel) && (!_channelInternetStatus[channel]) && _pubnetSystemActive)
  788. {
  789. if (_channelInternetRetry.ContainsKey(channel) && (_channelInternetRetry[channel] >= PUBNUB_NETWORK_CHECK_RETRIES))
  790. {
  791. WriteToLog(string.Format("DateTime {0}, Presence channel={1} - No internet connection. MAXed retries for internet ", DateTime.Now.ToString(), channel), TraceLevel.Info);
  792. presenceExceptionHandler<T>(channel, usercallback, true);
  793. return;
  794. }
  795. if (OVERRIDE_TCP_KEEP_ALIVE)
  796. {
  797. WriteToLog(string.Format("DateTime {0}, Presence - No internet connection for {1}", DateTime.Now.ToString(), channel), TraceLevel.Info);
  798. ReconnectState<T> netState = new ReconnectState<T>();
  799. netState.channel = channel;
  800. netState.type = ResponseType.Presence;
  801. netState.callback = usercallback;
  802. netState.timetoken = timetoken;
  803. reconnectNetwork<T>(netState);
  804. return;
  805. }
  806. }
  807. // Begin recursive subscribe
  808. try
  809. {
  810. // Build URL
  811. Uri request = buildPresenceRequest(channel, timetoken);
  812. // Wait for message
  813. _urlRequest<T>(request, channel, ResponseType.Presence, usercallback, reconnect);
  814. }
  815. catch (Exception ex)
  816. {
  817. WriteToLog(string.Format("method:_presence \n channel={0} \n timetoken={1} \n Exception Details={2}", channel, timetoken.ToString(), ex.ToString()), TraceLevel.Error);
  818. this._presence<T>(channel, timetoken, usercallback, false);
  819. }
  820. }
  821. public void presence_unsubscribe(string channel, Action<object> usercallback)
  822. {
  823. presence_unsubscribe<object>(channel, usercallback);
  824. }
  825. public void presence_unsubscribe<T>(string channel, Action<T> usercallback)
  826. {
  827. if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()))
  828. {
  829. throw new ArgumentException("Missing Channel");
  830. }
  831. channel = string.Format("{0}-pnpres", channel);
  832. bool unsubStatus = false;
  833. WriteToLog(string.Format("DateTime {0}, requested presence-unsubscribe for channel={1}", DateTime.Now.ToString(), channel), TraceLevel.Info);
  834. string jsonString = "";
  835. List<object> result = new List<object>();
  836. if (_channelPresence.ContainsKey(channel))
  837. {
  838. long unsubPreValue;
  839. unsubStatus = _channelPresence.TryRemove(channel, out unsubPreValue);
  840. if (unsubStatus)
  841. {
  842. if (_channelRequest.ContainsKey(channel))
  843. {
  844. HttpWebRequest storedRequest = _channelRequest[channel].request;
  845. storedRequest.Abort();
  846. }
  847. jsonString = string.Format("[1, \"Presence-Unsubscribed from {0}\"]", channel.Replace("-pnpres", ""));
  848. }
  849. else
  850. {
  851. jsonString = string.Format("[1, \"Error presence-unsubscribing from {0}\"]", channel.Replace("-pnpres", ""));
  852. }
  853. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  854. result.Add(channel.Replace("-pnpres", ""));
  855. WriteToLog(string.Format("DateTime {0}, JSON presence-unsubscribe response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  856. goToUserCallback<T>(result, usercallback);
  857. }
  858. else
  859. {
  860. result = new List<object>();
  861. jsonString = "[0, \"Channel Not Subscribed\"]";
  862. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  863. result.Add(channel.Replace("-pnpres", ""));
  864. WriteToLog(string.Format("DateTime {0}, JSON presence-unsubscribe response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  865. goToUserCallback<T>(result, usercallback);
  866. }
  867. }
  868. public bool here_now(string channel, Action<object> usercallback)
  869. {
  870. return here_now<object>(channel, usercallback);
  871. }
  872. public bool here_now<T>(string channel, Action<T> usercallback)
  873. {
  874. if (string.IsNullOrEmpty(channel) || string.IsNullOrEmpty(channel.Trim()))
  875. {
  876. throw new ArgumentException("Missing Channel");
  877. }
  878. Uri request = buildHereNowRequest(channel);
  879. return _urlRequest<T>(request, channel, ResponseType.Here_Now, usercallback, false);
  880. }
  881. /**
  882. * Time
  883. *
  884. * Timestamp from PubNub Cloud
  885. *
  886. * @return object timestamp.
  887. */
  888. public bool time(Action<object> usercallback)
  889. {
  890. return time<object>(usercallback);
  891. }
  892. public bool time<T>(Action<T> usercallback)
  893. {
  894. Uri request = buildTimeRequest();
  895. return _urlRequest<T>(request, "", ResponseType.Time, usercallback, false);
  896. }
  897. /**
  898. * Http Get Request
  899. *
  900. * @param List<string> request of URL directories.
  901. * @return List<object> from JSON response.
  902. */
  903. private bool _request(List<string> url_components, ResponseType type)
  904. {
  905. List<object> result = new List<object>();
  906. string channelName = getChannelName(url_components, type);
  907. StringBuilder url = new StringBuilder();
  908. // Add Origin To The Request
  909. url.Append(this.ORIGIN);
  910. // Generate URL with UTF-8 Encoding
  911. foreach (string url_bit in url_components)
  912. {
  913. url.Append("/");
  914. url.Append(_encodeURIcomponent(url_bit, type));
  915. }
  916. if (type == ResponseType.Presence || type == ResponseType.Subscribe)
  917. {
  918. url.Append("?uuid=");
  919. url.Append(this.sessionUUID);
  920. }
  921. if (type == ResponseType.DetailedHistory)
  922. url.Append(parameters);
  923. Uri requestUri = new Uri(url.ToString());
  924. #if ((!__MonoCS__) && (!SILVERLIGHT) && !WINDOWS_PHONE)
  925. // Force canonical path and query
  926. string paq = requestUri.PathAndQuery;
  927. FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
  928. ulong flags = (ulong)flagsFieldInfo.GetValue(requestUri);
  929. flags &= ~((ulong)0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  930. flagsFieldInfo.SetValue(requestUri, flags);
  931. #endif
  932. // Create Request
  933. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
  934. try
  935. {
  936. // Make request with the following inline Asynchronous callback
  937. IAsyncResult asyncResult = request.BeginGetResponse(new AsyncCallback((asynchronousResult) =>
  938. {
  939. HttpWebRequest aRequest = (HttpWebRequest)asynchronousResult.AsyncState;
  940. HttpWebResponse aResponse = (HttpWebResponse)aRequest.EndGetResponse(asynchronousResult);
  941. using (StreamReader streamReader = new StreamReader(aResponse.GetResponseStream()))
  942. {
  943. // Deserialize the result
  944. string jsonString = streamReader.ReadToEnd();
  945. result = WrapResultBasedOnResponseType(type, jsonString, channelName, false);
  946. }
  947. }), request
  948. );
  949. return true;
  950. }
  951. catch (System.Exception ex)
  952. {
  953. Console.WriteLine(ex.ToString());
  954. return false;
  955. }
  956. }
  957. /**
  958. * Http Get Request
  959. *
  960. * @param List<string> request of URL directories.
  961. * @return List<object> from JSON response.
  962. */
  963. private bool _urlRequest<T>(Uri requestUri, string channelName, ResponseType type, Action<T> usercallback, bool reconnect)
  964. {
  965. List<object> result = new List<object>();
  966. try
  967. {
  968. // Create Request
  969. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
  970. #if (!SILVERLIGHT && !WINDOWS_PHONE)
  971. request.Timeout = PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC * 1000;
  972. #endif
  973. if ((!_channelSubscription.ContainsKey(channelName) && type == ResponseType.Subscribe)
  974. || (!_channelPresence.ContainsKey(channelName) && type == ResponseType.Presence))
  975. {
  976. WriteToLog(string.Format("DateTime {0}, Due to Unsubscribe, request aborted for channel={1}", DateTime.Now.ToString(), channelName), TraceLevel.Info);
  977. request.Abort();
  978. }
  979. RequestState pubnubRequestState = new RequestState();
  980. pubnubRequestState.request = request;
  981. pubnubRequestState.channel = channelName;
  982. pubnubRequestState.type = type;
  983. if (type == ResponseType.Subscribe || type == ResponseType.Presence)
  984. {
  985. _channelRequest.AddOrUpdate(channelName, pubnubRequestState, (key, oldState) => pubnubRequestState);
  986. }
  987. if (OVERRIDE_TCP_KEEP_ALIVE)
  988. {
  989. //Eventhough heart-beat is disabled, run one time to check internet connection by setting dueTime=0
  990. heartBeatTimer = new System.Threading.Timer(
  991. new TimerCallback(OnPubnubHeartBeatTimeoutCallback), pubnubRequestState, 0,
  992. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? Timeout.Infinite : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  993. }
  994. else
  995. {
  996. #if ((!__MonoCS__) && (!SILVERLIGHT) && !WINDOWS_PHONE)
  997. request.ServicePoint.SetTcpKeepAlive(true, PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000, 1000);
  998. #endif
  999. }
  1000. WriteToLog(string.Format("DateTime {0}, Request={1}", DateTime.Now.ToString(), requestUri.ToString()), TraceLevel.Info);
  1001. // Make request with the following inline Asynchronous callback
  1002. IAsyncResult asyncResult = request.BeginGetResponse(new AsyncCallback((asynchronousResult) =>
  1003. {
  1004. try
  1005. {
  1006. RequestState asynchRequestState = (RequestState)asynchronousResult.AsyncState;
  1007. HttpWebRequest aRequest = (HttpWebRequest)asynchRequestState.request;
  1008. if (aRequest != null)
  1009. {
  1010. using (HttpWebResponse aResponse = (HttpWebResponse)aRequest.EndGetResponse(asynchronousResult))
  1011. {
  1012. pubnubRequestState.response = aResponse;
  1013. using (StreamReader streamReader = new StreamReader(aResponse.GetResponseStream()))
  1014. {
  1015. if (type == ResponseType.Subscribe || type == ResponseType.Presence)
  1016. {
  1017. _channelInternetStatus.AddOrUpdate(channelName, true, (key, oldValue) => true);
  1018. }
  1019. // Deserialize the result
  1020. string jsonString = streamReader.ReadToEnd();
  1021. streamReader.Close();
  1022. if (OVERRIDE_TCP_KEEP_ALIVE)
  1023. {
  1024. heartBeatTimer.Change(
  1025. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000,
  1026. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  1027. }
  1028. WriteToLog(string.Format("DateTime {0}, JSON for channel={1} ({2}) ={3}", DateTime.Now.ToString(), channelName, type.ToString(), jsonString), TraceLevel.Info);
  1029. result = WrapResultBasedOnResponseType(type, jsonString, channelName, reconnect);
  1030. }
  1031. aResponse.Close();
  1032. }
  1033. }
  1034. else
  1035. {
  1036. WriteToLog(string.Format("DateTime {0}, Request aborted for channel={1}", DateTime.Now.ToString(), channelName), TraceLevel.Info);
  1037. }
  1038. if (result != null && result.Count >= 1 && usercallback != null)
  1039. {
  1040. responseToUserCallback<T>(result, type, channelName, usercallback);
  1041. }
  1042. switch (type)
  1043. {
  1044. case ResponseType.Subscribe:
  1045. subscribeInternalCallback<T>(result, usercallback);
  1046. break;
  1047. case ResponseType.Presence:
  1048. presenceInternalCallback<T>(result, usercallback);
  1049. break;
  1050. default:
  1051. break;
  1052. }
  1053. }
  1054. catch (WebException webEx)
  1055. {
  1056. WriteToLog(string.Format("DateTime {0}, WebException: {1} for URL: {2}", DateTime.Now.ToString(), webEx.ToString(), requestUri.ToString()), TraceLevel.Error);
  1057. RequestState state = (RequestState)asynchronousResult.AsyncState;
  1058. if (state.response != null)
  1059. {
  1060. state.response.Close();
  1061. state.request.Abort();
  1062. }
  1063. #if (!SILVERLIGHT)
  1064. if ((webEx.Status == WebExceptionStatus.NameResolutionFailure //No network
  1065. || webEx.Status == WebExceptionStatus.ConnectFailure //Sending Keep-alive packet failed (No network)/Server is down.
  1066. || webEx.Status == WebExceptionStatus.ServerProtocolViolation//Problem with proxy or ISP
  1067. || webEx.Status == WebExceptionStatus.ProtocolError
  1068. ) && (!OVERRIDE_TCP_KEEP_ALIVE))
  1069. {
  1070. //internet connection problem.
  1071. WriteToLog(string.Format("DateTime {0}, _urlRequest - Internet connection problem", DateTime.Now.ToString()), TraceLevel.Error);
  1072. if (_channelInternetStatus.ContainsKey(channelName)
  1073. && (type == ResponseType.Subscribe || type == ResponseType.Presence))
  1074. {
  1075. if (_channelInternetStatus[channelName])
  1076. {
  1077. //Reset Retry if previous state is true
  1078. _channelInternetRetry.AddOrUpdate(channelName, 0, (key, oldValue) => 0);
  1079. }
  1080. else
  1081. {
  1082. _channelInternetRetry.AddOrUpdate(channelName, 1, (key, oldValue) => oldValue + 1);
  1083. WriteToLog(string.Format("DateTime {0} {1} channel = {2} _urlRequest - Internet connection retry {3} of {4}", DateTime.Now.ToString(), type, channelName, _channelInternetRetry[channelName], PUBNUB_NETWORK_CHECK_RETRIES), TraceLevel.Info);
  1084. }
  1085. _channelInternetStatus[channelName] = false;
  1086. Thread.Sleep(PUBNUB_WEBREQUEST_RETRY_INTERVAL_IN_SEC * 1000);
  1087. }
  1088. }
  1089. #endif
  1090. urlRequestCommonExceptionHandler<T>(type, channelName, usercallback);
  1091. }
  1092. catch (Exception ex)
  1093. {
  1094. RequestState state = (RequestState)asynchronousResult.AsyncState;
  1095. if (state.response != null)
  1096. state.response.Close();
  1097. WriteToLog(string.Format("DateTime {0} Exception= {1} for URL: {2}", DateTime.Now.ToString(), ex.ToString(), requestUri.ToString()), TraceLevel.Error);
  1098. urlRequestCommonExceptionHandler<T>(type, channelName, usercallback);
  1099. }
  1100. }), pubnubRequestState);
  1101. #if (__MonoCS__)
  1102. if (!asyncResult.AsyncWaitHandle.WaitOne(PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC * 1000))
  1103. {
  1104. OnPubnubWebRequestTimeout(pubnubRequestState, true);
  1105. }
  1106. #elif (SILVERLIGHT || WINDOWS_PHONE)
  1107. Timer webRequestTimer = new Timer(OnPubnubWebRequestTimeout, pubnubRequestState, PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC * 1000, Timeout.Infinite);
  1108. #else
  1109. ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, new WaitOrTimerCallback(OnPubnubWebRequestTimeout), pubnubRequestState, PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC * 1000, true);
  1110. #endif
  1111. return true;
  1112. }
  1113. catch (System.Exception ex)
  1114. {
  1115. WriteToLog(string.Format("DateTime {0} Exception={1}", DateTime.Now.ToString(), ex.ToString()), TraceLevel.Error);
  1116. urlRequestCommonExceptionHandler<T>(type, channelName, usercallback);
  1117. return false;
  1118. }
  1119. }
  1120. public Uri buildTimeRequest()
  1121. {
  1122. List<string> url = new List<string>();
  1123. url.Add("time");
  1124. url.Add("0");
  1125. return buildRestApiRequest<Uri>(url, ResponseType.Time);
  1126. }
  1127. private Uri buildLeaveRequest(string channel)
  1128. {
  1129. List<string> url = new List<string>();
  1130. url.Add("v2");
  1131. url.Add("presence");
  1132. url.Add("sub_key");
  1133. url.Add(this.SUBSCRIBE_KEY);
  1134. url.Add("channel");
  1135. url.Add(channel);
  1136. url.Add("leave");
  1137. return buildRestApiRequest<Uri>(url, ResponseType.Leave);
  1138. }
  1139. private Uri buildHereNowRequest(string channel)
  1140. {
  1141. List<string> url = new List<string>();
  1142. url.Add("v2");
  1143. url.Add("presence");
  1144. url.Add("sub_key");
  1145. url.Add(this.SUBSCRIBE_KEY);
  1146. url.Add("channel");
  1147. url.Add(channel);
  1148. return buildRestApiRequest<Uri>(url, ResponseType.Here_Now);
  1149. }
  1150. private Uri buildDetailedHistoryRequest(string channel, long start, long end, int count, bool reverse)
  1151. {
  1152. parameters = "";
  1153. if (count <= -1) count = 100;
  1154. parameters = "?count=" + count;
  1155. if (reverse)
  1156. parameters = parameters + "&" + "reverse=" + reverse.ToString().ToLower();
  1157. if (start != -1)
  1158. parameters = parameters + "&" + "start=" + start.ToString().ToLower();
  1159. if (end != -1)
  1160. parameters = parameters + "&" + "end=" + end.ToString().ToLower();
  1161. List<string> url = new List<string>();
  1162. url.Add("v2");
  1163. url.Add("history");
  1164. url.Add("sub-key");
  1165. url.Add(this.SUBSCRIBE_KEY);
  1166. url.Add("channel");
  1167. url.Add(channel);
  1168. return buildRestApiRequest<Uri>(url, ResponseType.DetailedHistory);
  1169. }
  1170. private Uri buildSubscribeRequest(string channel, object timetoken)
  1171. {
  1172. List<string> url = new List<string>();
  1173. url.Add("subscribe");
  1174. url.Add(this.SUBSCRIBE_KEY);
  1175. url.Add(channel);
  1176. url.Add("0");
  1177. url.Add(timetoken.ToString());
  1178. return buildRestApiRequest<Uri>(url, ResponseType.Subscribe);
  1179. }
  1180. private Uri buildPresenceRequest(string channel, object timetoken)
  1181. {
  1182. List<string> url = new List<string>();
  1183. url.Add("subscribe");
  1184. url.Add(this.SUBSCRIBE_KEY);
  1185. url.Add(channel);
  1186. url.Add("0");
  1187. url.Add(timetoken.ToString());
  1188. return buildRestApiRequest<Uri>(url, ResponseType.Presence);
  1189. }
  1190. private Uri buildPublishRequest(string channel, object message)
  1191. {
  1192. string msg = jsonEncodePublishMsg(message);
  1193. // Generate String to Sign
  1194. string signature = "0";
  1195. if (this.SECRET_KEY.Length > 0)
  1196. {
  1197. StringBuilder string_to_sign = new StringBuilder();
  1198. string_to_sign
  1199. .Append(this.PUBLISH_KEY)
  1200. .Append('/')
  1201. .Append(this.SUBSCRIBE_KEY)
  1202. .Append('/')
  1203. .Append(this.SECRET_KEY)
  1204. .Append('/')
  1205. .Append(channel)
  1206. .Append('/')
  1207. .Append(msg); // 1
  1208. // Sign Message
  1209. signature = md5(string_to_sign.ToString());
  1210. }
  1211. // Build URL
  1212. List<string> url = new List<string>();
  1213. url.Add("publish");
  1214. url.Add(this.PUBLISH_KEY);
  1215. url.Add(this.SUBSCRIBE_KEY);
  1216. url.Add(signature);
  1217. url.Add(channel);
  1218. url.Add("0");
  1219. url.Add(msg);
  1220. return buildRestApiRequest<Uri>(url, ResponseType.Publish);
  1221. }
  1222. private Uri buildRestApiRequest<T>(List<string> url_components, ResponseType type)
  1223. {
  1224. StringBuilder url = new StringBuilder();
  1225. // Add Origin To The Request
  1226. url.Append(this.ORIGIN);
  1227. // Generate URL with UTF-8 Encoding
  1228. foreach (string url_bit in url_components)
  1229. {
  1230. url.Append("/");
  1231. url.Append(_encodeURIcomponent(url_bit, type));
  1232. }
  1233. if (type == ResponseType.Presence || type == ResponseType.Subscribe || type == ResponseType.Leave)
  1234. {
  1235. url.Append("?uuid=");
  1236. url.Append(this.sessionUUID);
  1237. }
  1238. if (type == ResponseType.DetailedHistory)
  1239. url.Append(parameters);
  1240. Uri requestUri = new Uri(url.ToString());
  1241. #if ((!__MonoCS__) && (!SILVERLIGHT) && (!WINDOWS_PHONE))
  1242. if ((type == ResponseType.Publish || type == ResponseType.Subscribe || type == ResponseType.Presence))
  1243. {
  1244. // Force canonical path and query
  1245. string paq = requestUri.PathAndQuery;
  1246. FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
  1247. ulong flags = (ulong)flagsFieldInfo.GetValue(requestUri);
  1248. flags &= ~((ulong)0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  1249. flagsFieldInfo.SetValue(requestUri, flags);
  1250. }
  1251. #endif
  1252. return requestUri;
  1253. }
  1254. void OnPubnubWebRequestTimeout(Object reqState)
  1255. {
  1256. RequestState currentState = reqState as RequestState;
  1257. if (currentState != null && currentState.response == null && currentState.request != null)
  1258. {
  1259. currentState.request.Abort();
  1260. WriteToLog(string.Format("DateTime: {0}, **WP7 OnPubnubWebRequestTimeout**", DateTime.Now.ToString()), TraceLevel.Error);
  1261. }
  1262. }
  1263. private void urlRequestCommonExceptionHandler<T>(ResponseType type, string channelName, Action<T> usercallback)
  1264. {
  1265. if (type == ResponseType.Subscribe)
  1266. {
  1267. subscribeExceptionHandler<T>(channelName, usercallback, false);
  1268. }
  1269. else if (type == ResponseType.Presence)
  1270. {
  1271. presenceExceptionHandler<T>(channelName, usercallback, false);
  1272. }
  1273. else if (type == ResponseType.Publish)
  1274. {
  1275. publishExceptionHandler<T>(channelN

Large files files are truncated, but you can click here to view the full file