PageRenderTime 64ms CodeModel.GetById 18ms 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
  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>(channelName, usercallback);
  1276. }
  1277. else if (type == ResponseType.Here_Now)
  1278. {
  1279. hereNowExceptionHandler<T>(channelName, usercallback);
  1280. }
  1281. else if (type == ResponseType.DetailedHistory)
  1282. {
  1283. detailedHistoryExceptionHandler<T>(channelName, usercallback);
  1284. }
  1285. else if (type == ResponseType.Time)
  1286. {
  1287. timeExceptionHandler<T>(usercallback);
  1288. }
  1289. else if (type == ResponseType.Leave)
  1290. {
  1291. //no action at this time
  1292. }
  1293. }
  1294. private void responseToUserCallback<T>(List<object> result, ResponseType type, string channelName, Action<T> usercallback) //where T: class//, new()
  1295. {
  1296. switch (type)
  1297. {
  1298. case ResponseType.Subscribe:
  1299. var msgs = (from item in result
  1300. select item as object).ToArray();
  1301. if (msgs != null && msgs.Length > 0)
  1302. {
  1303. List<object> msgList = msgs[0] as List<object>;
  1304. if (msgList != null && msgList.Count > 0)
  1305. {
  1306. foreach (object item in msgList)
  1307. {
  1308. List<object> itemMsg = new List<object>();
  1309. itemMsg.Add(item);
  1310. for (int index = 1; index < msgs.Length; index++)
  1311. {
  1312. itemMsg.Add(msgs[index]);
  1313. }
  1314. goToUserCallback<T>(itemMsg, usercallback);
  1315. }
  1316. }
  1317. }
  1318. removeChannelRequest(channelName);
  1319. break;
  1320. case ResponseType.Presence:
  1321. var msgp = (from item in result
  1322. select item as object).ToArray();
  1323. if (msgp != null && msgp.Length > 0)
  1324. {
  1325. JArray msgArr = msgp[0] as JArray;
  1326. if (msgArr != null && msgArr.Count > 0)
  1327. {
  1328. foreach (object item in msgArr)
  1329. {
  1330. List<object> itemMsg = new List<object>();
  1331. itemMsg.Add(item);
  1332. for (int index = 1; index < msgp.Length; index++)
  1333. {
  1334. if (index == 2)
  1335. {
  1336. msgp[index] = ((string)msgp[index]).Replace("-pnpres", "");
  1337. }
  1338. itemMsg.Add(msgp[index]);
  1339. }
  1340. goToUserCallback<T>(itemMsg, usercallback);
  1341. }
  1342. }
  1343. }
  1344. removeChannelRequest(channelName);
  1345. break;
  1346. case ResponseType.Publish:
  1347. if (result != null && result.Count > 0)
  1348. {
  1349. goToUserCallback<T>(result, usercallback);
  1350. }
  1351. break;
  1352. case ResponseType.DetailedHistory:
  1353. if (result != null && result.Count > 0)
  1354. {
  1355. goToUserCallback<T>(result, usercallback);
  1356. }
  1357. break;
  1358. case ResponseType.Here_Now:
  1359. if (result != null && result.Count > 0)
  1360. {
  1361. goToUserCallback<T>(result, usercallback);
  1362. }
  1363. break;
  1364. case ResponseType.Time:
  1365. if (result != null && result.Count > 0)
  1366. {
  1367. goToUserCallback<T>(result, usercallback);
  1368. }
  1369. break;
  1370. case ResponseType.Leave:
  1371. //No response to callback
  1372. break;
  1373. default:
  1374. break;
  1375. }
  1376. }
  1377. private void jsonResponseToUserCallback<T>(List<object> result, Action<T> usercallback)
  1378. {
  1379. string usercallbackJSON = "";
  1380. if (typeof(T) == typeof(string))
  1381. {
  1382. usercallbackJSON = JsonConvert.SerializeObject(result);
  1383. Action<string> castUserCallback = usercallback as Action<string>;
  1384. castUserCallback(usercallbackJSON);
  1385. }
  1386. }
  1387. private void removeChannelRequest(string channelName)
  1388. {
  1389. if (_channelRequest.ContainsKey(channelName))
  1390. {
  1391. RequestState currentReq = _channelRequest[channelName];
  1392. currentReq.request = null;
  1393. currentReq.response = null;
  1394. bool remove = _channelRequest.TryRemove(channelName, out currentReq);
  1395. if (!remove)
  1396. {
  1397. WriteToLog(string.Format("DateTime {0} Unable to remove request from dictionary for channel ={1}", DateTime.Now.ToString(), channelName), TraceLevel.Error);
  1398. }
  1399. }
  1400. }
  1401. private void subscribeExceptionHandler<T>(string channelName, Action<T> usercallback, bool reconnectTried)
  1402. {
  1403. if (reconnectTried)
  1404. {
  1405. WriteToLog(string.Format("DateTime {0}, MAX retries reached. Exiting the subscribe for channel = {1}", DateTime.Now.ToString(), channelName), TraceLevel.Info);
  1406. unsubscribe(channelName, null);
  1407. List<object> errorResult = new List<object>();
  1408. string jsonString = string.Format("[0, \"Unsubscribed after {0} failed retries\"]", PUBNUB_NETWORK_CHECK_RETRIES);
  1409. errorResult = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1410. errorResult.Add(channelName);
  1411. WriteToLog(string.Format("DateTime {0}, Subscribe JSON network error response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  1412. if (usercallback != null)
  1413. {
  1414. goToUserCallback<T>(errorResult, usercallback);
  1415. }
  1416. }
  1417. else
  1418. {
  1419. List<object> result = new List<object>();
  1420. result.Add("0");
  1421. if (_subscribeMsg.ContainsKey(channelName))
  1422. {
  1423. List<object> lastResult = _subscribeMsg[channelName] as List<object>;
  1424. result.Add((lastResult != null) ? lastResult[1] : "0"); //get last timetoken
  1425. }
  1426. else
  1427. {
  1428. result.Add("0"); //timetoken
  1429. }
  1430. result.Add(channelName); //send channel name
  1431. subscribeInternalCallback<T>(result, usercallback);
  1432. }
  1433. }
  1434. private void presenceExceptionHandler<T>(string channelName, Action<T> usercallback, bool reconnectTry)
  1435. {
  1436. if (reconnectTry)
  1437. {
  1438. WriteToLog(string.Format("DateTime {0}, MAX retries reached. Exiting the presence for channel = {1}", DateTime.Now.ToString(), channelName), TraceLevel.Info);
  1439. presence_unsubscribe(channelName.Replace("-pnpres", ""), null);
  1440. List<object> errorResult = new List<object>();
  1441. string jsonString = string.Format("[0, \"Presence-unsubscribed after {0} failed retries\"]", PUBNUB_NETWORK_CHECK_RETRIES);
  1442. errorResult = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1443. errorResult.Add(channelName);
  1444. WriteToLog(string.Format("DateTime {0}, Presence JSON network error response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  1445. if (usercallback != null)
  1446. {
  1447. goToUserCallback<T>(errorResult, usercallback);
  1448. }
  1449. }
  1450. else
  1451. {
  1452. List<object> result = new List<object>();
  1453. result.Add("0");
  1454. if (_presenceMsg.ContainsKey(channelName))
  1455. {
  1456. List<object> lastResult = _presenceMsg[channelName] as List<object>;
  1457. result.Add((lastResult != null) ? lastResult[1] : "0"); //get last timetoken
  1458. }
  1459. else
  1460. {
  1461. result.Add("0"); //timetoken
  1462. }
  1463. result.Add(channelName); //send channel name
  1464. presenceInternalCallback<T>(result, usercallback);
  1465. }
  1466. }
  1467. private void publishExceptionHandler<T>(string channelName, Action<T> usercallback)
  1468. {
  1469. List<object> result = new List<object>();
  1470. string jsonString = "[0, \"Network connnect error\"]";
  1471. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1472. result.Add(channelName);
  1473. WriteToLog(string.Format("DateTime {0}, JSON publish response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  1474. goToUserCallback<T>(result, usercallback);
  1475. }
  1476. private void hereNowExceptionHandler<T>(string channelName, Action<T> usercallback)
  1477. {
  1478. List<object> result = new List<object>();
  1479. string jsonString = "[0, \"Network connnect error\"]";
  1480. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1481. result.Add(channelName);
  1482. WriteToLog(string.Format("DateTime {0}, JSON here_now response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  1483. goToUserCallback<T>(result, usercallback);
  1484. }
  1485. private void detailedHistoryExceptionHandler<T>(string channelName, Action<T> usercallback)
  1486. {
  1487. List<object> result = new List<object>();
  1488. string jsonString = "[0, \"Network connnect error\"]";
  1489. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1490. result.Add(channelName);
  1491. WriteToLog(string.Format("DateTime {0}, JSON detailedHistoryExceptionHandler response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  1492. goToUserCallback<T>(result, usercallback);
  1493. }
  1494. private void timeExceptionHandler<T>(Action<T> usercallback)
  1495. {
  1496. List<object> result = new List<object>();
  1497. string jsonString = "[0, \"Network connnect error\"]";
  1498. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1499. WriteToLog(string.Format("DateTime {0}, JSON timeExceptionHandler response={1}", DateTime.Now.ToString(), jsonString), TraceLevel.Info);
  1500. goToUserCallback<T>(result, usercallback);
  1501. }
  1502. /// <summary>
  1503. /// Gets the result by wrapping the json response based on the request
  1504. /// </summary>
  1505. /// <param name="type"></param>
  1506. /// <param name="jsonString"></param>
  1507. /// <param name="url_components"></param>
  1508. /// <returns></returns>
  1509. private List<object> WrapResultBasedOnResponseType(ResponseType type, string jsonString, string channelName, bool reconnect)
  1510. {
  1511. List<object> result = new List<object>();
  1512. object objResult = JsonConvert.DeserializeObject<object>(jsonString);
  1513. List<object> result1 = ((IEnumerable)objResult).Cast<object>().ToList();
  1514. if (result1 != null && result1.Count > 0)
  1515. {
  1516. result = decodeMsg(result1, type);
  1517. }
  1518. switch (type)
  1519. {
  1520. case ResponseType.Publish:
  1521. result.Add(channelName);
  1522. _publishMsg.AddOrUpdate(channelName, result, (key, oldValue) => result);
  1523. break;
  1524. case ResponseType.History:
  1525. if (this.CIPHER_KEY.Length > 0)
  1526. {
  1527. List<object> historyDecrypted = new List<object>();
  1528. PubnubCrypto aes = new PubnubCrypto(this.CIPHER_KEY);
  1529. foreach (object message in result)
  1530. {
  1531. historyDecrypted.Add(aes.decrypt(message.ToString()));
  1532. }
  1533. History = historyDecrypted;
  1534. }
  1535. else
  1536. {
  1537. History = result;
  1538. }
  1539. break;
  1540. case ResponseType.DetailedHistory:
  1541. result.Add(channelName);
  1542. break;
  1543. case ResponseType.Here_Now:
  1544. Dictionary<string, object> dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
  1545. result = new List<object>();
  1546. result.Add(dic);
  1547. result.Add(channelName);
  1548. break;
  1549. case ResponseType.Time:
  1550. _Time = result;
  1551. break;
  1552. case ResponseType.Subscribe:
  1553. result.Add(channelName);
  1554. _subscribeMsg.AddOrUpdate(channelName, result, (key, oldValue) =>
  1555. {
  1556. if (reconnect)
  1557. {
  1558. List<object> oldResult = oldValue as List<object>;
  1559. if (oldResult != null)
  1560. {
  1561. result[1] = oldResult[1];
  1562. }
  1563. return result;
  1564. }
  1565. else
  1566. {
  1567. return result;
  1568. }
  1569. });
  1570. break;
  1571. case ResponseType.Presence:
  1572. result.Add(channelName);
  1573. _presenceMsg.AddOrUpdate(channelName, result, (key, oldValue) =>
  1574. {
  1575. if (reconnect)
  1576. {
  1577. List<object> oldResult = oldValue as List<object>;
  1578. if (oldResult != null)
  1579. {
  1580. result[1] = oldResult[1];
  1581. }
  1582. return result;
  1583. }
  1584. else
  1585. {
  1586. return result;
  1587. }
  1588. });
  1589. break;
  1590. case ResponseType.Leave:
  1591. result.Add(channelName);
  1592. break;
  1593. default:
  1594. break;
  1595. };//switch stmt end
  1596. return result;
  1597. }
  1598. private void goToUserCallback<T>(List<object> result, Action<T> usercallback)
  1599. {
  1600. if (usercallback != null)
  1601. {
  1602. if (typeof(T) == typeof(string))
  1603. {
  1604. jsonResponseToUserCallback(result, usercallback);
  1605. }
  1606. else
  1607. {
  1608. usercallback((T)(IList)result.AsReadOnly());
  1609. }
  1610. }
  1611. }
  1612. /// <summary>
  1613. /// Retrieves the channel name from the url components
  1614. /// </summary>
  1615. /// <param name="url_components"></param>
  1616. /// <param name="type"></param>
  1617. /// <returns></returns>
  1618. private string getChannelName(List<string> url_components, ResponseType type)
  1619. {
  1620. string channelName = "";
  1621. switch (type)
  1622. {
  1623. case ResponseType.Subscribe:
  1624. channelName = url_components[2];
  1625. break;
  1626. case ResponseType.Publish:
  1627. channelName = url_components[4];
  1628. break;
  1629. case ResponseType.Presence:
  1630. channelName = url_components[2];
  1631. break;
  1632. case ResponseType.DetailedHistory:
  1633. channelName = url_components[5];
  1634. break;
  1635. case ResponseType.Here_Now:
  1636. channelName = url_components[5];
  1637. break;
  1638. case ResponseType.Leave:
  1639. channelName = url_components[5];
  1640. break;
  1641. default:
  1642. break;
  1643. };
  1644. return channelName;
  1645. }
  1646. // Serialize the given object into JSON string
  1647. public static string SerializeToJsonString(object objectToSerialize)
  1648. {
  1649. return JsonConvert.SerializeObject(objectToSerialize);
  1650. }
  1651. // Deserialize JSON string into List of Objects
  1652. public static List<object> DeserializeToListOfObject(string jsonString)
  1653. {
  1654. return JsonConvert.DeserializeObject<List<object>>(jsonString);
  1655. }
  1656. private string _encodeURIcomponent(string s, ResponseType type)
  1657. {
  1658. string encodedURI = "";
  1659. StringBuilder o = new StringBuilder();
  1660. foreach (char ch in s.ToCharArray())
  1661. {
  1662. if (isUnsafe(ch))
  1663. {
  1664. o.Append('%');
  1665. o.Append(toHex(ch / 16));
  1666. o.Append(toHex(ch % 16));
  1667. }
  1668. else o.Append(ch);
  1669. }
  1670. encodedURI = o.ToString();
  1671. if (type == ResponseType.Here_Now || type == ResponseType.DetailedHistory || type == ResponseType.Leave)
  1672. {
  1673. encodedURI = encodedURI.Replace("%2F", "%252F");
  1674. }
  1675. return encodedURI;
  1676. }
  1677. private char toHex(int ch)
  1678. {
  1679. return (char)(ch < 10 ? '0' + ch : 'A' + ch - 10);
  1680. }
  1681. private bool isUnsafe(char ch)
  1682. {
  1683. return " ~`!@#$%^&*()+=[]\\{}|;':\",./<>?".IndexOf(ch) >= 0;
  1684. }
  1685. public Guid generateGUID()
  1686. {
  1687. return Guid.NewGuid();
  1688. }
  1689. private static string md5(string text)
  1690. {
  1691. MD5 md5 = new MD5CryptoServiceProvider();
  1692. byte[] data = Encoding.Unicode.GetBytes(text);
  1693. byte[] hash = md5.ComputeHash(data);
  1694. string hexaHash = "";
  1695. foreach (byte b in hash) hexaHash += String.Format("{0:x2}", b);
  1696. return hexaHash;
  1697. }
  1698. private static void WriteToLog(string str, TraceLevel traceLevel)
  1699. {
  1700. if (CAPTURE_TRACE_LEVEL != TraceLevel.Off)
  1701. {
  1702. if (CAPTURE_TRACE_LEVEL == TraceLevel.Error && traceLevel == TraceLevel.Error)
  1703. {
  1704. #if (SILVERLIGHT || WINDOWS_PHONE)
  1705. Debug.WriteLine(str);
  1706. //AlternateTraceWriteLine(str);
  1707. #else
  1708. Trace.WriteLine(str);
  1709. #endif
  1710. }
  1711. else if (CAPTURE_TRACE_LEVEL == TraceLevel.Warning
  1712. && (traceLevel == TraceLevel.Error || traceLevel == TraceLevel.Warning))
  1713. {
  1714. #if (SILVERLIGHT || WINDOWS_PHONE)
  1715. Debug.WriteLine(str);
  1716. //AlternateTraceWriteLine(str);
  1717. #else
  1718. Trace.WriteLine(str);
  1719. #endif
  1720. }
  1721. else if (CAPTURE_TRACE_LEVEL == TraceLevel.Info
  1722. && (traceLevel == TraceLevel.Error || traceLevel == TraceLevel.Warning || traceLevel == TraceLevel.Info))
  1723. {
  1724. #if (SILVERLIGHT || WINDOWS_PHONE)
  1725. Debug.WriteLine(str);
  1726. //AlternateTraceWriteLine(str);
  1727. #else
  1728. Trace.WriteLine(str);
  1729. #endif
  1730. }
  1731. else
  1732. {
  1733. #if (SILVERLIGHT || WINDOWS_PHONE)
  1734. Debug.WriteLine(str);
  1735. #else
  1736. Trace.WriteLine(str);
  1737. #endif
  1738. }
  1739. }
  1740. }
  1741. //private static void AlternateTraceWriteLine(string str)
  1742. //{
  1743. // try
  1744. // {
  1745. // IsolatedStorageFile storageFile = IsolatedStorageFile.GetUserStoreForApplication();
  1746. // if (!storageFile.DirectoryExists("pubnubmessaging"))
  1747. // {
  1748. // storageFile.CreateDirectory("pubnubmessaging");
  1749. // }
  1750. // string fileFullPath = @"pubnubmessaging\trace.log";
  1751. // if (!storageFile.FileExists(fileFullPath))
  1752. // {
  1753. // //storageFile.DeleteFile(fileFullPath);
  1754. // //return;
  1755. // storageFile.CreateFile(fileFullPath);
  1756. // }
  1757. // else
  1758. // {
  1759. // //check the size of the file
  1760. // //storageFile.AvailableFreeSpace
  1761. // }
  1762. // using (IsolatedStorageFileStream storageFileStream = storageFile.OpenFile(fileFullPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite))
  1763. // {
  1764. // //long fileSize = storageFileStream.cu
  1765. // using (StreamWriter writer = new StreamWriter(storageFileStream))
  1766. // {
  1767. // writer.WriteLine(str);
  1768. // writer.Flush();
  1769. // writer.Close();
  1770. // }
  1771. // storageFileStream.Close();
  1772. // }
  1773. // }
  1774. // catch
  1775. // {
  1776. // }
  1777. //}
  1778. //public static string AlternateTraceReader()
  1779. //{
  1780. // string ret = "";
  1781. // try
  1782. // {
  1783. // IsolatedStorageFile storageFile = IsolatedStorageFile.GetUserStoreForApplication();
  1784. // if (!storageFile.DirectoryExists("pubnubmessaging"))
  1785. // {
  1786. // throw new DirectoryNotFoundException("pubnubmessaging dir missing");
  1787. // }
  1788. // string fileFullPath = @"pubnubmessaging\trace.log";
  1789. // if (!storageFile.FileExists(fileFullPath))
  1790. // {
  1791. // throw new FileNotFoundException("trace.log file missing");
  1792. // }
  1793. // using (IsolatedStorageFileStream storageFileStream = storageFile.OpenFile(fileFullPath, FileMode.Open, FileAccess.Read, FileShare.Read))
  1794. // {
  1795. // using (StreamReader reader = new StreamReader(storageFileStream))
  1796. // {
  1797. // ret = reader.ReadToEnd();
  1798. // reader.Close();
  1799. // }
  1800. // storageFileStream.Close();
  1801. // }
  1802. // }
  1803. // catch (Exception ex)
  1804. // {
  1805. // ret = ex.ToString();
  1806. // }
  1807. // return ret;
  1808. //}
  1809. public static long translateDateTimeToPubnubUnixNanoSeconds(DateTime dotNetUTCDateTime)
  1810. {
  1811. TimeSpan ts = dotNetUTCDateTime - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
  1812. long timestamp = Convert.ToInt64(ts.TotalSeconds) * 10000000;
  1813. return timestamp;
  1814. }
  1815. public static DateTime translatePubnubUnixNanoSecondsToDateTime(long unixNanoSecondTime)
  1816. {
  1817. double timestamp = unixNanoSecondTime / 10000000;
  1818. DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp);
  1819. return dt;
  1820. }
  1821. }
  1822. #if (SILVERLIGHT || WINDOWS_PHONE)
  1823. public enum TraceLevel
  1824. {
  1825. Off = 0,
  1826. Error = 1,
  1827. Warning = 2,
  1828. Info = 3,
  1829. Verbose = 4,
  1830. }
  1831. #endif
  1832. /// <summary>
  1833. /// MD5 Service provider
  1834. /// </summary>
  1835. internal class MD5CryptoServiceProvider : MD5
  1836. {
  1837. public MD5CryptoServiceProvider()
  1838. : base()
  1839. {
  1840. }
  1841. }
  1842. /// <summary>
  1843. /// MD5 messaging-digest algorithm is a widely used cryptographic hash function that produces 128-bit hash value.
  1844. /// </summary>
  1845. internal class MD5 : IDisposable
  1846. {
  1847. static public MD5 Create(string hashName)
  1848. {
  1849. if (hashName == "MD5")
  1850. return new MD5();
  1851. else
  1852. throw new NotSupportedException();
  1853. }
  1854. static public String GetMd5String(String source)
  1855. {
  1856. MD5 md = MD5CryptoServiceProvider.Create();
  1857. byte[] hash;
  1858. //Create a new instance of ASCIIEncoding to
  1859. //convert the string into an array of Unicode bytes.
  1860. UTF8Encoding enc = new UTF8Encoding();
  1861. // ASCIIEncoding enc = new ASCIIEncoding();
  1862. //Convert the string into an array of bytes.
  1863. byte[] buffer = enc.GetBytes(source);
  1864. //Create the hash value from the array of bytes.
  1865. hash = md.ComputeHash(buffer);
  1866. StringBuilder sb = new StringBuilder();
  1867. foreach (byte b in hash)
  1868. sb.Append(b.ToString("x2"));
  1869. return sb.ToString();
  1870. }
  1871. static public MD5 Create()
  1872. {
  1873. return new MD5();
  1874. }
  1875. #region base implementation of the MD5
  1876. #region constants
  1877. private const byte S11 = 7;
  1878. private const byte S12 = 12;
  1879. private const byte S13 = 17;
  1880. private const byte S14 = 22;
  1881. private const byte S21 = 5;
  1882. private const byte S22 = 9;
  1883. private const byte S23 = 14;
  1884. private const byte S24 = 20;
  1885. private const byte S31 = 4;
  1886. private const byte S32 = 11;
  1887. private const byte S33 = 16;
  1888. private const byte S34 = 23;
  1889. private const byte S41 = 6;
  1890. private const byte S42 = 10;
  1891. private const byte S43 = 15;
  1892. private const byte S44 = 21;
  1893. static private byte[] PADDING = new byte[] {
  1894. 0x80, 0, 0, 0, 0, 0,
  1895. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1896. 0, 0, 0, 0, 0, 0, 0,
  1897. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1898. 0, 0, 0, 0, 0, 0, 0,
  1899. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  1900. };
  1901. #endregion
  1902. #region F, G, H and I are basic MD5 functions.
  1903. static private uint F(uint x, uint y, uint z)
  1904. {
  1905. return (((x) & (y)) | ((~x) & (z)));
  1906. }
  1907. static private uint G(uint x, uint y, uint z)
  1908. {
  1909. return (((x) & (z)) | ((y) & (~z)));
  1910. }
  1911. static private uint H(uint x, uint y, uint z)
  1912. {
  1913. return ((x) ^ (y) ^ (z));
  1914. }
  1915. static private uint I(uint x, uint y, uint z)
  1916. {
  1917. return ((y) ^ ((x) | (~z)));
  1918. }
  1919. #endregion
  1920. #region rotates x left n bits.
  1921. /// <summary>
  1922. /// rotates x left n bits.
  1923. /// </summary>
  1924. /// <param name="x"></param>
  1925. /// <param name="n"></param>
  1926. /// <returns></returns>
  1927. static private uint ROTATE_LEFT(uint x, byte n)
  1928. {
  1929. return (((x) << (n)) | ((x) >> (32 - (n))));
  1930. }
  1931. #endregion
  1932. #region FF, GG, HH, and II transformations
  1933. /// FF, GG, HH, and II transformations
  1934. /// for rounds 1, 2, 3, and 4.
  1935. /// Rotation is separate from addition to prevent re-computation.
  1936. static private void FF(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac)
  1937. {
  1938. (a) += F((b), (c), (d)) + (x) + (uint)(ac);
  1939. (a) = ROTATE_LEFT((a), (s));
  1940. (a) += (b);
  1941. }
  1942. static private void GG(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac)
  1943. {
  1944. (a) += G((b), (c), (d)) + (x) + (uint)(ac);
  1945. (a) = ROTATE_LEFT((a), (s));
  1946. (a) += (b);
  1947. }
  1948. static private void HH(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac)
  1949. {
  1950. (a) += H((b), (c), (d)) + (x) + (uint)(ac);
  1951. (a) = ROTATE_LEFT((a), (s));
  1952. (a) += (b);
  1953. }
  1954. static private void II(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac)
  1955. {
  1956. (a) += I((b), (c), (d)) + (x) + (uint)(ac);
  1957. (a) = ROTATE_LEFT((a), (s));
  1958. (a) += (b);
  1959. }
  1960. #endregion
  1961. #region context info
  1962. /// <summary>
  1963. /// state (ABCD)
  1964. /// </summary>
  1965. uint[] state = new uint[4];
  1966. /// <summary>
  1967. /// number of bits, modulo 2^64 (LSB first)
  1968. /// </summary>
  1969. uint[] count = new uint[2];
  1970. /// <summary>
  1971. /// input buffer
  1972. /// </summary>
  1973. byte[] buffer = new byte[64];
  1974. #endregion
  1975. internal MD5()
  1976. {
  1977. Initialize();
  1978. }
  1979. /// <summary>
  1980. /// MD5 initialization. Begins an MD5 operation, writing a new context.
  1981. /// </summary>
  1982. /// <remarks>
  1983. /// The RFC named it "MD5Init"
  1984. /// </remarks>
  1985. public virtual void Initialize()
  1986. {
  1987. count[0] = count[1] = 0;
  1988. // Load magic initialization constants.
  1989. state[0] = 0x67452301;
  1990. state[1] = 0xefcdab89;
  1991. state[2] = 0x98badcfe;
  1992. state[3] = 0x10325476;
  1993. }
  1994. /// <summary>
  1995. /// MD5 block update operation. Continues an MD5 message-digest
  1996. /// operation, processing another message block, and updating the
  1997. /// context.
  1998. /// </summary>
  1999. /// <param name="input"></param>
  2000. /// <param name="offset"></param>
  2001. /// <param name="count"></param>
  2002. /// <remarks>The RFC Named it MD5Update</remarks>
  2003. protected virtual void HashCore(byte[] input, int offset, int count)
  2004. {
  2005. int i;
  2006. int index;
  2007. int partLen;
  2008. // Compute number of bytes mod 64
  2009. index = (int)((this.count[0] >> 3) & 0x3F);
  2010. // Update number of bits
  2011. if ((this.count[0] += (uint)((uint)count << 3)) < ((uint)count << 3))
  2012. this.count[1]++;
  2013. this.count[1] += ((uint)count >> 29);
  2014. partLen = 64 - index;
  2015. // Transform as many times as possible.
  2016. if (count >= partLen)
  2017. {
  2018. Buffer.BlockCopy(input, offset, this.buffer, index, partLen);
  2019. Transform(this.buffer, 0);
  2020. for (i = partLen; i + 63 < count; i += 64)
  2021. Transform(input, offset + i);
  2022. index = 0;
  2023. }
  2024. else
  2025. i = 0;
  2026. // Buffer remaining input
  2027. Buffer.BlockCopy(input, offset + i, this.buffer, index, count - i);
  2028. }
  2029. /// <summary>
  2030. /// MD5 finalization. Ends an MD5 message-digest operation, writing the
  2031. /// the message digest and zeroizing the context.
  2032. /// </summary>
  2033. /// <returns>message digest</returns>
  2034. /// <remarks>The RFC named it MD5Final</remarks>
  2035. protected virtual byte[] HashFinal()
  2036. {
  2037. byte[] digest = new byte[16];
  2038. byte[] bits = new byte[8];
  2039. int index, padLen;
  2040. // Save number of bits
  2041. Encode(bits, 0, this.count, 0, 8);
  2042. // Pad out to 56 mod 64.
  2043. index = (int)((uint)(this.count[0] >> 3) & 0x3f);
  2044. padLen = (index < 56) ? (56 - index) : (120 - index);
  2045. HashCore(PADDING, 0, padLen);
  2046. // Append length (before padding)
  2047. HashCore(bits, 0, 8);
  2048. // Store state in digest
  2049. Encode(digest, 0, state, 0, 16);
  2050. // Zeroize sensitive information.
  2051. count[0] = count[1] = 0;
  2052. state[0] = 0;
  2053. state[1] = 0;
  2054. state[2] = 0;
  2055. state[3] = 0;
  2056. // initialize again, to be ready to use
  2057. Initialize();
  2058. return digest;
  2059. }
  2060. /// <summary>
  2061. /// MD5 basic transformation. Transforms state based on 64 bytes block.
  2062. /// </summary>
  2063. /// <param name="block"></param>
  2064. /// <param name="offset"></param>
  2065. private void Transform(byte[] block, int offset)
  2066. {
  2067. uint a = state[0], b = state[1], c = state[2], d = state[3];
  2068. uint[] x = new uint[16];
  2069. Decode(x, 0, block, offset, 64);
  2070. // Round 1
  2071. FF(ref a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
  2072. FF(ref d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
  2073. FF(ref c, d, a, b, x[2], S13, 0x242070db); /* 3 */
  2074. FF(ref b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
  2075. FF(ref a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
  2076. FF(ref d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
  2077. FF(ref c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
  2078. FF(ref b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
  2079. FF(ref a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
  2080. FF(ref d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
  2081. FF(ref c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
  2082. FF(ref b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
  2083. FF(ref a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
  2084. FF(ref d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
  2085. FF(ref c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
  2086. FF(ref b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
  2087. // Round 2
  2088. GG(ref a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
  2089. GG(ref d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
  2090. GG(ref c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
  2091. GG(ref b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
  2092. GG(ref a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
  2093. GG(ref d, a, b, c, x[10], S22, 0x2441453); /* 22 */
  2094. GG(ref c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
  2095. GG(ref b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
  2096. GG(ref a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
  2097. GG(ref d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
  2098. GG(ref c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
  2099. GG(ref b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
  2100. GG(ref a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
  2101. GG(ref d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
  2102. GG(ref c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
  2103. GG(ref b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
  2104. // Round 3
  2105. HH(ref a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
  2106. HH(ref d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
  2107. HH(ref c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
  2108. HH(ref b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
  2109. HH(ref a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
  2110. HH(ref d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
  2111. HH(ref c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
  2112. HH(ref b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
  2113. HH(ref a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
  2114. HH(ref d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
  2115. HH(ref c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
  2116. HH(ref b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
  2117. HH(ref a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
  2118. HH(ref d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
  2119. HH(ref c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
  2120. HH(ref b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
  2121. // Round 4
  2122. II(ref a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
  2123. II(ref d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
  2124. II(ref c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
  2125. II(ref b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
  2126. II(ref a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
  2127. II(ref d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
  2128. II(ref c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
  2129. II(ref b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
  2130. II(ref a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
  2131. II(ref d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
  2132. II(ref c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
  2133. II(ref b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
  2134. II(ref a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
  2135. II(ref d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
  2136. II(ref c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
  2137. II(ref b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
  2138. state[0] += a;
  2139. state[1] += b;
  2140. state[2] += c;
  2141. state[3] += d;
  2142. // Zeroize sensitive information.
  2143. for (int i = 0; i < x.Length; i++)
  2144. x[i] = 0;
  2145. }
  2146. /// <summary>
  2147. /// Encodes input (uint) into output (byte). Assumes len is
  2148. /// multiple of 4.
  2149. /// </summary>
  2150. /// <param name="output"></param>
  2151. /// <param name="outputOffset"></param>
  2152. /// <param name="input"></param>
  2153. /// <param name="inputOffset"></param>
  2154. /// <param name="count"></param>
  2155. private static void Encode(byte[] output, int outputOffset, uint[] input, int inputOffset, int count)
  2156. {
  2157. int i, j;
  2158. int end = outputOffset + count;
  2159. for (i = inputOffset, j = outputOffset; j < end; i++, j += 4)
  2160. {
  2161. output[j] = (byte)(input[i] & 0xff);
  2162. output[j + 1] = (byte)((input[i] >> 8) & 0xff);
  2163. output[j + 2] = (byte)((input[i] >> 16) & 0xff);
  2164. output[j + 3] = (byte)((input[i] >> 24) & 0xff);
  2165. }
  2166. }
  2167. /// <summary>
  2168. /// Decodes input (byte) into output (uint). Assumes len is
  2169. /// a multiple of 4.
  2170. /// </summary>
  2171. /// <param name="output"></param>
  2172. /// <param name="outputOffset"></param>
  2173. /// <param name="input"></param>
  2174. /// <param name="inputOffset"></param>
  2175. /// <param name="count"></param>
  2176. static private void Decode(uint[] output, int outputOffset, byte[] input, int inputOffset, int count)
  2177. {
  2178. int i, j;
  2179. int end = inputOffset + count;
  2180. for (i = outputOffset, j = inputOffset; j < end; i++, j += 4)
  2181. output[i] = ((uint)input[j]) | (((uint)input[j + 1]) << 8) | (((uint)input[j + 2]) << 16) | (((uint)input[j + 3]) <<
  2182. 24);
  2183. }
  2184. #endregion
  2185. #region expose the same interface as the regular MD5 object
  2186. protected byte[] HashValue;
  2187. protected int State;
  2188. public virtual bool CanReuseTransform
  2189. {
  2190. get
  2191. {
  2192. return true;
  2193. }
  2194. }
  2195. public virtual bool CanTransformMultipleBlocks
  2196. {
  2197. get
  2198. {
  2199. return true;
  2200. }
  2201. }
  2202. public virtual byte[] Hash
  2203. {
  2204. get
  2205. {
  2206. if (this.State != 0)
  2207. throw new InvalidOperationException();
  2208. return (byte[])HashValue.Clone();
  2209. }
  2210. }
  2211. public virtual int HashSize
  2212. {
  2213. get
  2214. {
  2215. return HashSizeValue;
  2216. }
  2217. }
  2218. protected int HashSizeValue = 128;
  2219. public virtual int InputBlockSize
  2220. {
  2221. get
  2222. {
  2223. return 1;
  2224. }
  2225. }
  2226. public virtual int OutputBlockSize
  2227. {
  2228. get
  2229. {
  2230. return 1;
  2231. }
  2232. }
  2233. public void Clear()
  2234. {
  2235. Dispose(true);
  2236. }
  2237. public byte[] ComputeHash(byte[] buffer)
  2238. {
  2239. return ComputeHash(buffer, 0, buffer.Length);
  2240. }
  2241. public byte[] ComputeHash(byte[] buffer, int offset, int count)
  2242. {
  2243. Initialize();
  2244. HashCore(buffer, offset, count);
  2245. HashValue = HashFinal();
  2246. return (byte[])HashValue.Clone();
  2247. }
  2248. public byte[] ComputeHash(Stream inputStream)
  2249. {
  2250. Initialize();
  2251. int count;
  2252. byte[] buffer = new byte[4096];
  2253. while (0 < (count = inputStream.Read(buffer, 0, 4096)))
  2254. {
  2255. HashCore(buffer, 0, count);
  2256. }
  2257. HashValue = HashFinal();
  2258. return (byte[])HashValue.Clone();
  2259. }
  2260. public int TransformBlock(
  2261. byte[] inputBuffer,
  2262. int inputOffset,
  2263. int inputCount,
  2264. byte[] outputBuffer,
  2265. int outputOffset
  2266. )
  2267. {
  2268. if (inputBuffer == null)
  2269. {
  2270. throw new ArgumentNullException("inputBuffer");
  2271. }
  2272. if (inputOffset < 0)
  2273. {
  2274. throw new ArgumentOutOfRangeException("inputOffset");
  2275. }
  2276. if ((inputCount < 0) || (inputCount > inputBuffer.Length))
  2277. {
  2278. throw new ArgumentException("inputCount");
  2279. }
  2280. if ((inputBuffer.Length - inputCount) < inputOffset)
  2281. {
  2282. throw new ArgumentOutOfRangeException("inputOffset");
  2283. }
  2284. if (this.State == 0)
  2285. {
  2286. Initialize();
  2287. this.State = 1;
  2288. }
  2289. HashCore(inputBuffer, inputOffset, inputCount);
  2290. if ((inputBuffer != outputBuffer) || (inputOffset != outputOffset))
  2291. {
  2292. Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
  2293. }
  2294. return inputCount;
  2295. }
  2296. public byte[] TransformFinalBlock(
  2297. byte[] inputBuffer,
  2298. int inputOffset,
  2299. int inputCount
  2300. )
  2301. {
  2302. if (inputBuffer == null)
  2303. {
  2304. throw new ArgumentNullException("inputBuffer");
  2305. }
  2306. if (inputOffset < 0)
  2307. {
  2308. throw new ArgumentOutOfRangeException("inputOffset");
  2309. }
  2310. if ((inputCount < 0) || (inputCount > inputBuffer.Length))
  2311. {
  2312. throw new ArgumentException("inputCount");
  2313. }
  2314. if ((inputBuffer.Length - inputCount) < inputOffset)
  2315. {
  2316. throw new ArgumentOutOfRangeException("inputOffset");
  2317. }
  2318. if (this.State == 0)
  2319. {
  2320. Initialize();
  2321. }
  2322. HashCore(inputBuffer, inputOffset, inputCount);
  2323. HashValue = HashFinal();
  2324. byte[] buffer = new byte[inputCount];
  2325. Buffer.BlockCopy(inputBuffer, inputOffset, buffer, 0, inputCount);
  2326. this.State = 0;
  2327. return buffer;
  2328. }
  2329. #endregion
  2330. protected virtual void Dispose(bool disposing)
  2331. {
  2332. if (!disposing)
  2333. Initialize();
  2334. }
  2335. public void Dispose()
  2336. {
  2337. Dispose(true);
  2338. }
  2339. }
  2340. public class PubnubCrypto
  2341. {
  2342. private string CIPHER_KEY = "";
  2343. public PubnubCrypto(string cipher_key)
  2344. {
  2345. this.CIPHER_KEY = cipher_key;
  2346. }
  2347. /// <summary>
  2348. /// Computes the hash using the specified algo
  2349. /// </summary>
  2350. /// <returns>
  2351. /// The hash.
  2352. /// </returns>
  2353. /// <param name='input'>
  2354. /// Input string
  2355. /// </param>
  2356. /// <param name='algorithm'>
  2357. /// Algorithm to use for Hashing
  2358. /// </param>
  2359. private static string ComputeHash(string input, HashAlgorithm algorithm)
  2360. {
  2361. #if (SILVERLIGHT || WINDOWS_PHONE)
  2362. Byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
  2363. #else
  2364. Byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
  2365. #endif
  2366. Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);
  2367. return BitConverter.ToString(hashedBytes);
  2368. }
  2369. private string GetEncryptionKey()
  2370. {
  2371. //Compute Hash using the SHA256
  2372. #if (SILVERLIGHT || WINDOWS_PHONE)
  2373. string strKeySHA256HashRaw = ComputeHash(this.CIPHER_KEY, new System.Security.Cryptography.SHA256Managed());
  2374. #else
  2375. string strKeySHA256HashRaw = ComputeHash(this.CIPHER_KEY, new SHA256CryptoServiceProvider());
  2376. #endif
  2377. //delete the "-" that appear after every 2 chars
  2378. string strKeySHA256Hash = (strKeySHA256HashRaw.Replace("-", "")).Substring(0, 32);
  2379. //convert to lower case
  2380. return strKeySHA256Hash.ToLower();
  2381. }
  2382. /**
  2383. * EncryptOrDecrypt
  2384. *
  2385. * Basic function for encrypt or decrypt a string
  2386. * for encrypt type = true
  2387. * for decrypt type = false
  2388. */
  2389. private string EncryptOrDecrypt(bool type, string plainStr)
  2390. {
  2391. #if (SILVERLIGHT || WINDOWS_PHONE)
  2392. AesManaged aesEncryption = new AesManaged();
  2393. aesEncryption.KeySize = 256;
  2394. aesEncryption.BlockSize = 128;
  2395. //get ASCII bytes of the string
  2396. aesEncryption.IV = System.Text.Encoding.UTF8.GetBytes("0123456789012345");
  2397. aesEncryption.Key = System.Text.Encoding.UTF8.GetBytes(GetEncryptionKey());
  2398. #else
  2399. RijndaelManaged aesEncryption = new RijndaelManaged();
  2400. aesEncryption.KeySize = 256;
  2401. aesEncryption.BlockSize = 128;
  2402. //Mode CBC
  2403. aesEncryption.Mode = CipherMode.CBC;
  2404. //padding
  2405. aesEncryption.Padding = PaddingMode.PKCS7;
  2406. //get ASCII bytes of the string
  2407. aesEncryption.IV = System.Text.Encoding.ASCII.GetBytes("0123456789012345");
  2408. aesEncryption.Key = System.Text.Encoding.ASCII.GetBytes(GetEncryptionKey());
  2409. #endif
  2410. if (type)
  2411. {
  2412. ICryptoTransform crypto = aesEncryption.CreateEncryptor();
  2413. plainStr = EncodeNonAsciiCharacters(plainStr);
  2414. #if (SILVERLIGHT || WINDOWS_PHONE)
  2415. byte[] plainText = Encoding.UTF8.GetBytes(plainStr);
  2416. #else
  2417. byte[] plainText = Encoding.ASCII.GetBytes(plainStr);
  2418. #endif
  2419. //encrypt
  2420. byte[] cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length);
  2421. return Convert.ToBase64String(cipherText);
  2422. }
  2423. else
  2424. {
  2425. try
  2426. {
  2427. ICryptoTransform decrypto = aesEncryption.CreateDecryptor();
  2428. //decode
  2429. byte[] decryptedBytes = Convert.FromBase64CharArray(plainStr.ToCharArray(), 0, plainStr.Length);
  2430. //decrypt
  2431. #if (SILVERLIGHT || WINDOWS_PHONE)
  2432. var data = decrypto.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length);
  2433. string strDecrypted = Encoding.UTF8.GetString(data, 0, data.Length);
  2434. #else
  2435. string strDecrypted = System.Text.Encoding.ASCII.GetString(decrypto.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length));
  2436. #endif
  2437. return strDecrypted;
  2438. }
  2439. catch(Exception ex)
  2440. {
  2441. return "**DECRYPT ERROR**";
  2442. }
  2443. }
  2444. }
  2445. // encrypt string
  2446. public string encrypt(string plainStr)
  2447. {
  2448. if (plainStr == null || plainStr.Length <= 0) throw new ArgumentNullException("plainStr");
  2449. return EncryptOrDecrypt(true, plainStr);
  2450. }
  2451. // decrypt string
  2452. public string decrypt(string cipherStr)
  2453. {
  2454. if (cipherStr == null) throw new ArgumentNullException("cipherStr");
  2455. return EncryptOrDecrypt(false, cipherStr);
  2456. }
  2457. //md5 used for AES encryption key
  2458. private static byte[] md5(string cipher_key)
  2459. {
  2460. MD5 obj = new MD5CryptoServiceProvider();
  2461. #if (SILVERLIGHT || WINDOWS_PHONE)
  2462. byte[] data = Encoding.UTF8.GetBytes(cipher_key);
  2463. #else
  2464. byte[] data = Encoding.Default.GetBytes(cipher_key);
  2465. #endif
  2466. return obj.ComputeHash(data);
  2467. }
  2468. /// <summary>
  2469. /// Encodes the non ASCII characters.
  2470. /// </summary>
  2471. /// <returns>
  2472. /// The non ASCII characters.
  2473. /// </returns>
  2474. /// <param name='value'>
  2475. /// Value.
  2476. /// </param>
  2477. private string EncodeNonAsciiCharacters(string value)
  2478. {
  2479. StringBuilder sb = new StringBuilder();
  2480. foreach (char c in value)
  2481. {
  2482. if (c > 127)
  2483. {
  2484. // This character is too big for ASCII
  2485. string encodedValue = "\\u" + ((int)c).ToString("x4");
  2486. sb.Append(encodedValue);
  2487. }
  2488. else
  2489. {
  2490. sb.Append(c);
  2491. }
  2492. }
  2493. return sb.ToString();
  2494. }
  2495. }
  2496. internal enum ResponseType
  2497. {
  2498. Publish,
  2499. History,
  2500. Time,
  2501. Subscribe,
  2502. Presence,
  2503. Here_Now,
  2504. DetailedHistory,
  2505. Leave
  2506. }
  2507. internal class ReconnectState<T>
  2508. {
  2509. public string channel;
  2510. public ResponseType type;
  2511. public Action<T> callback;
  2512. public object timetoken;
  2513. public ReconnectState()
  2514. {
  2515. channel = "";
  2516. callback = null;
  2517. timetoken = null;
  2518. }
  2519. }
  2520. internal class RequestState
  2521. {
  2522. public HttpWebRequest request;
  2523. public HttpWebResponse response;
  2524. public ResponseType type;
  2525. public string channel;
  2526. public RequestState()
  2527. {
  2528. request = null;
  2529. response = null;
  2530. channel = "";
  2531. }
  2532. }
  2533. internal class InternetState
  2534. {
  2535. public Action<bool> callback;
  2536. public IPAddress ipaddr;
  2537. public InternetState()
  2538. {
  2539. callback = null;
  2540. ipaddr = null;
  2541. }
  2542. }
  2543. internal class ClientNetworkStatus
  2544. {
  2545. const TraceLevel CAPTURE_TRACE_LEVEL = TraceLevel.Error;
  2546. private static bool _status = true;
  2547. //private static TraceSwitch appSwitch = new TraceSwitch("PubnubTraceSwitch", "Pubnub Trace Switch in config file");
  2548. #if (SILVERLIGHT || WINDOWS_PHONE)
  2549. private static ManualResetEvent mres = new ManualResetEvent(false);
  2550. private static ManualResetEvent mreSocketAsync = new ManualResetEvent(false);
  2551. #else
  2552. private static ManualResetEventSlim mres = new ManualResetEventSlim(false);
  2553. #endif
  2554. internal static void checkInternetStatus(bool systemActive, Action<bool> callback)
  2555. {
  2556. if (callback != null)
  2557. {
  2558. try
  2559. {
  2560. if (systemActive)
  2561. {
  2562. checkClientNetworkAvailability(callback);
  2563. }
  2564. else
  2565. {
  2566. callback(false);
  2567. }
  2568. }
  2569. catch (Exception ex)
  2570. {
  2571. WriteToLog(string.Format("DateTime {0} checkInternetStatus Error. {1}", DateTime.Now.ToString(), ex.ToString()), TraceLevel.Error);
  2572. }
  2573. }
  2574. }
  2575. internal static bool checkInternetStatus(bool systemActive)
  2576. {
  2577. checkClientNetworkAvailability(callbackClientNetworkStatus);
  2578. return _status;
  2579. }
  2580. private static void callbackClientNetworkStatus(bool status)
  2581. {
  2582. _status = status;
  2583. }
  2584. private static void checkClientNetworkAvailability(Action<bool> callback)
  2585. {
  2586. InternetState state = new InternetState();
  2587. state.callback = callback;
  2588. ThreadPool.QueueUserWorkItem(checkSocketConnect, state);
  2589. #if (SILVERLIGHT || WINDOWS_PHONE)
  2590. mres.WaitOne();
  2591. #else
  2592. mres.Wait();
  2593. #endif
  2594. }
  2595. private static void checkSocketConnect(object internetState)
  2596. {
  2597. InternetState state = internetState as InternetState;
  2598. Action<bool> callback = state.callback;
  2599. try
  2600. {
  2601. #if (SILVERLIGHT || WINDOWS_PHONE)
  2602. using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
  2603. {
  2604. SocketAsyncEventArgs sae = new SocketAsyncEventArgs();
  2605. sae.UserToken = state;
  2606. sae.RemoteEndPoint = new DnsEndPoint("pubsub.pubnub.com", 80);
  2607. sae.Completed += new EventHandler<SocketAsyncEventArgs>(socketAsync_Completed);
  2608. bool test = socket.ConnectAsync(sae);
  2609. mreSocketAsync.WaitOne(1000);
  2610. socket.Close();
  2611. }
  2612. #else
  2613. using (UdpClient udp = new UdpClient("pizza.pubnub.com", 80))
  2614. {
  2615. IPAddress localAddr = ((IPEndPoint)udp.Client.LocalEndPoint).Address;
  2616. udp.Close();
  2617. WriteToLog(string.Format("DateTime {0} checkInternetStatus LocalIP: {1}", DateTime.Now.ToString(), localAddr.ToString()), TraceLevel.Verbose);
  2618. callback(true);
  2619. }
  2620. #endif
  2621. }
  2622. catch (Exception ex)
  2623. {
  2624. WriteToLog(string.Format("DateTime {0} checkInternetStatus Error. {1}", DateTime.Now.ToString(), ex.ToString()), TraceLevel.Error);
  2625. callback(false);
  2626. }
  2627. mres.Set();
  2628. }
  2629. #if (SILVERLIGHT || WINDOWS_PHONE)
  2630. static void socketAsync_Completed(object sender, SocketAsyncEventArgs e)
  2631. {
  2632. if (e.LastOperation == SocketAsyncOperation.Connect)
  2633. {
  2634. Socket skt = sender as Socket;
  2635. InternetState state = e.UserToken as InternetState;
  2636. if (state != null)
  2637. {
  2638. WriteToLog(string.Format("DateTime {0} socketAsync_Completed.", DateTime.Now.ToString()), TraceLevel.Info);
  2639. state.callback(true);
  2640. }
  2641. mreSocketAsync.Set();
  2642. }
  2643. }
  2644. #endif
  2645. private static void WriteToLog(string str, TraceLevel traceLevel)
  2646. {
  2647. if (CAPTURE_TRACE_LEVEL != TraceLevel.Off)
  2648. {
  2649. if (CAPTURE_TRACE_LEVEL == TraceLevel.Error && traceLevel == TraceLevel.Error)
  2650. {
  2651. #if (SILVERLIGHT || WINDOWS_PHONE)
  2652. Debug.WriteLine(str);
  2653. #else
  2654. Trace.WriteLine(str);
  2655. #endif
  2656. }
  2657. else if (CAPTURE_TRACE_LEVEL == TraceLevel.Warning
  2658. && (traceLevel == TraceLevel.Error || traceLevel == TraceLevel.Warning))
  2659. {
  2660. #if (SILVERLIGHT || WINDOWS_PHONE)
  2661. Debug.WriteLine(str);
  2662. #else
  2663. Trace.WriteLine(str);
  2664. #endif
  2665. }
  2666. else if (CAPTURE_TRACE_LEVEL == TraceLevel.Info
  2667. && (traceLevel == TraceLevel.Error || traceLevel == TraceLevel.Warning || traceLevel == TraceLevel.Info))
  2668. {
  2669. #if (SILVERLIGHT || WINDOWS_PHONE)
  2670. Debug.WriteLine(str);
  2671. #else
  2672. Trace.WriteLine(str);
  2673. #endif
  2674. }
  2675. else
  2676. {
  2677. #if (SILVERLIGHT || WINDOWS_PHONE)
  2678. Debug.WriteLine(str);
  2679. #else
  2680. Trace.WriteLine(str);
  2681. #endif
  2682. }
  2683. }
  2684. }
  2685. }
  2686. }