PageRenderTime 74ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 1ms

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

https://github.com/jhey/pubnub-api
C# | 2925 lines | 2303 code | 308 blank | 314 comment | 408 complexity | 5cc62c7e952711fdebf1d493cd848207 MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using System.Net;
  5. using System.Collections;
  6. using System.Collections.Generic;
  7. using System.Security.Cryptography;
  8. using System.Runtime.Serialization;
  9. using System.Runtime.Serialization.Json;
  10. using System.ComponentModel;
  11. using System.Reflection;
  12. using System.Web.Script.Serialization;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  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. using System.Linq;
  22. using System.Text.RegularExpressions;
  23. using Newtonsoft.Json;
  24. using Newtonsoft.Json.Linq;
  25. namespace PubNub_Messaging2
  26. {
  27. // INotifyPropertyChanged provides a standard event for objects to notify clients that one of its properties has changed
  28. public class PubnubBase : INotifyPropertyChanged
  29. {
  30. const int PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC = 310;
  31. const int PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC = 15;
  32. const int PUBNUB_NETWORK_CHECK_RETRIES = 50;
  33. const int PUBNUB_WEBREQUEST_RETRY_INTERVAL_IN_SEC = 10;
  34. // Common property changed event
  35. public event PropertyChangedEventHandler PropertyChanged;
  36. public void RaisePropertyChanged(string propertyName)
  37. {
  38. var handler = PropertyChanged;
  39. if (handler != null)
  40. {
  41. handler(this, new PropertyChangedEventArgs(propertyName));
  42. }
  43. }
  44. ConcurrentDictionary<string, long> _channelSubscription = new ConcurrentDictionary<string, long>();
  45. ConcurrentDictionary<string, long> _channelPresence = new ConcurrentDictionary<string, long>();
  46. ConcurrentDictionary<string, RequestState> _channelRequest = new ConcurrentDictionary<string, RequestState>();
  47. ConcurrentDictionary<string, bool> _channelInternetStatus = new ConcurrentDictionary<string, bool>();
  48. ConcurrentDictionary<string, int> _channelInternetRetry = new ConcurrentDictionary<string, int>();
  49. ConcurrentDictionary<string, Timer> _channelReconnectTimer = new ConcurrentDictionary<string, Timer>();
  50. System.Threading.Timer heartBeatTimer;
  51. private static bool _pubnetSystemActive = true;
  52. private static TraceSwitch appSwitch = new TraceSwitch("PubnubTraceSwitch", "Pubnub Trace Switch in config file");
  53. // Publish
  54. private ConcurrentDictionary<string, object> _publishMsg = new ConcurrentDictionary<string, object>();
  55. // History of Messages
  56. private List<object> _History = new List<object>();
  57. public List<object> History { get { return _History; } set { _History = value; RaisePropertyChanged("History"); } }
  58. // Subscribe
  59. private ConcurrentDictionary<string, object> _subscribeMsg = new ConcurrentDictionary<string, object>();
  60. // Presence
  61. private ConcurrentDictionary<string, object> _presenceMsg = new ConcurrentDictionary<string, object>();
  62. // Timestamp
  63. private List<object> _Time = new List<object>();
  64. private bool _overrideTcpKeepAlive = false;
  65. // Pubnub Core API implementation
  66. private string ORIGIN = "pubsub.pubnub.com";
  67. private int LIMIT = 1800; // Temporary setup, remove limit as server will handle this.
  68. private string PUBLISH_KEY = "";
  69. private string SUBSCRIBE_KEY = "";
  70. private string SECRET_KEY = "";
  71. private string CIPHER_KEY = "";
  72. private bool SSL = false;
  73. private string sessionUUID = "";
  74. private string parameters = "";
  75. /**
  76. * Pubnub instance initialization function
  77. *
  78. * @param string pubish_key.
  79. * @param string subscribe_key.
  80. * @param string secret_key.
  81. * @param bool ssl_on
  82. */
  83. private void init(string publish_key, string subscribe_key, string secret_key, string cipher_key, bool ssl_on)
  84. {
  85. this.PUBLISH_KEY = publish_key;
  86. this.SUBSCRIBE_KEY = subscribe_key;
  87. this.SECRET_KEY = secret_key;
  88. this.CIPHER_KEY = cipher_key;
  89. this.SSL = ssl_on;
  90. if (this.sessionUUID == "")
  91. this.sessionUUID = Guid.NewGuid().ToString();
  92. // SSL is ON?
  93. if (this.SSL)
  94. this.ORIGIN = "https://" + this.ORIGIN;
  95. else
  96. this.ORIGIN = "http://" + this.ORIGIN;
  97. _overrideTcpKeepAlive = Boolean.Parse(ConfigurationManager.AppSettings["OverrideTcpKeepAlive"].ToString());
  98. //Initiate System Events for PowerModeChanged - to monitor suspend/resume
  99. initiatePowerModeCheck();
  100. }
  101. private void reconnectNetwork<T>(ReconnectState<T> netState)
  102. {
  103. System.Threading.Timer timer = new Timer(new TimerCallback(reconnectNetworkCallback<T>), netState, 0, PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  104. _channelReconnectTimer.AddOrUpdate(netState.channel, timer, (key, oldState) => timer);
  105. }
  106. void reconnectNetworkCallback<T>(Object reconnectState)
  107. {
  108. try
  109. {
  110. ReconnectState<T> netState = reconnectState as ReconnectState<T>;
  111. if (netState != null)
  112. {
  113. if (_channelInternetStatus.ContainsKey(netState.channel)
  114. && (netState.type == ResponseType.Subscribe || netState.type == ResponseType.Presence))
  115. {
  116. if (_channelInternetStatus[netState.channel])
  117. {
  118. //Reset Retry if previous state is true
  119. _channelInternetRetry.AddOrUpdate(netState.channel, 0, (key, oldValue) => 0);
  120. }
  121. else
  122. {
  123. _channelInternetRetry.AddOrUpdate(netState.channel, 1, (key, oldValue) => oldValue + 1);
  124. Trace.WriteLine(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));
  125. }
  126. }
  127. if (_channelInternetStatus[netState.channel])
  128. {
  129. if (_channelReconnectTimer.ContainsKey(netState.channel))
  130. {
  131. _channelReconnectTimer[netState.channel].Change(Timeout.Infinite, Timeout.Infinite);
  132. _channelReconnectTimer[netState.channel].Dispose();
  133. }
  134. if (appSwitch.TraceInfo)
  135. {
  136. Trace.WriteLine(string.Format("DateTime {0}, {1} {2} reconnectNetworkCallback. Internet Available : {3}", DateTime.Now.ToString(), netState.channel, netState.type, _channelInternetStatus[netState.channel]));
  137. }
  138. switch (netState.type)
  139. {
  140. case ResponseType.Subscribe:
  141. _subscribe(netState.channel, netState.timetoken, netState.callback, false);
  142. break;
  143. case ResponseType.Presence:
  144. _presence(netState.channel, netState.timetoken, netState.callback, false);
  145. break;
  146. default:
  147. break;
  148. }
  149. }
  150. else if (_channelInternetRetry[netState.channel] >= PUBNUB_NETWORK_CHECK_RETRIES)
  151. {
  152. if (_channelReconnectTimer.ContainsKey(netState.channel))
  153. {
  154. _channelReconnectTimer[netState.channel].Change(Timeout.Infinite, Timeout.Infinite);
  155. _channelReconnectTimer[netState.channel].Dispose();
  156. }
  157. switch (netState.type)
  158. {
  159. case ResponseType.Subscribe:
  160. subscribeExceptionHandler(netState.channel, netState.callback, true);
  161. break;
  162. case ResponseType.Presence:
  163. presenceExceptionHandler(netState.channel, netState.callback, true);
  164. break;
  165. default:
  166. break;
  167. }
  168. }
  169. }
  170. else
  171. {
  172. if (appSwitch.TraceError)
  173. {
  174. Trace.WriteLine(string.Format("DateTime {0}, Unknown request state in reconnectNetworkCallback", DateTime.Now.ToString()));
  175. }
  176. }
  177. }
  178. catch (Exception ex)
  179. {
  180. if (appSwitch.TraceError)
  181. {
  182. Trace.WriteLine(string.Format("DateTime {0} method:reconnectNetworkCallback \n Exception Details={1}", DateTime.Now.ToString(), ex.ToString()));
  183. }
  184. }
  185. }
  186. private void initiatePowerModeCheck()
  187. {
  188. try
  189. {
  190. SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
  191. if (appSwitch.TraceInfo)
  192. {
  193. Trace.WriteLine(string.Format("DateTime {0}, Initiated System Event - PowerModeChanged.", DateTime.Now.ToString()));
  194. }
  195. }
  196. catch(Exception ex)
  197. {
  198. if (appSwitch.TraceError)
  199. {
  200. Trace.WriteLine(string.Format("DateTime {0} No support for System Event - PowerModeChanged.", DateTime.Now.ToString()));
  201. Trace.WriteLine(string.Format("DateTime {0} {1}", DateTime.Now.ToString(),ex.ToString()));
  202. }
  203. }
  204. }
  205. void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
  206. {
  207. if (e.Mode == PowerModes.Suspend)
  208. {
  209. _pubnetSystemActive = false;
  210. TerminatePendingWebRequest();
  211. if (_overrideTcpKeepAlive)
  212. {
  213. heartBeatTimer.Change(Timeout.Infinite, Timeout.Infinite);
  214. }
  215. if (appSwitch.TraceInfo)
  216. {
  217. Trace.WriteLine(string.Format("DateTime {0}, System entered into Suspend Mode.", DateTime.Now.ToString()));
  218. if (_overrideTcpKeepAlive)
  219. {
  220. Trace.WriteLine(string.Format("DateTime {0}, Disabled Timer for heartbeat ", DateTime.Now.ToString()));
  221. }
  222. }
  223. }
  224. else if (e.Mode == PowerModes.Resume)
  225. {
  226. _pubnetSystemActive = true;
  227. if (_overrideTcpKeepAlive)
  228. {
  229. heartBeatTimer.Change(
  230. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000,
  231. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  232. }
  233. if (appSwitch.TraceInfo)
  234. {
  235. Trace.WriteLine(string.Format("DateTime {0}, System entered into Resume/Awake Mode.", DateTime.Now.ToString()));
  236. if (_overrideTcpKeepAlive)
  237. {
  238. Trace.WriteLine(string.Format("DateTime {0}, Enabled Timer for heartbeat ", DateTime.Now.ToString()));
  239. }
  240. }
  241. }
  242. }
  243. private void TerminatePendingWebRequest()
  244. {
  245. TerminatePendingWebRequest(null);
  246. }
  247. private void TerminatePendingWebRequest(RequestState state)
  248. {
  249. if (state != null && state.request != null)
  250. {
  251. state.request.Abort();
  252. if (appSwitch.TraceInfo)
  253. {
  254. Trace.WriteLine(string.Format("DateTime {0} TerminatePendingWebRequest {1}", DateTime.Now.ToString(), state.request.RequestUri.ToString()));
  255. }
  256. RequestState removedReq;
  257. bool removeKey = _channelRequest.TryRemove(state.channel, out removedReq);
  258. if (!removeKey && appSwitch.TraceError)
  259. {
  260. Trace.WriteLine(string.Format("DateTime {0} Unable to remove web request from dictionary in TerminatePendingWebRequest for channel= {1}", DateTime.Now.ToString(), state.channel));
  261. }
  262. }
  263. else
  264. {
  265. ConcurrentDictionary<string, RequestState> webReq = _channelRequest;
  266. ICollection<string> keyCol = _channelRequest.Keys;
  267. foreach (string key in keyCol)
  268. {
  269. RequestState currReq = _channelRequest[key];
  270. if (currReq.request != null)
  271. {
  272. currReq.request.Abort();
  273. if (appSwitch.TraceInfo)
  274. {
  275. Trace.WriteLine(string.Format("DateTime {0} TerminatePendingWebRequest {1}", DateTime.Now.ToString(), currReq.request.RequestUri.ToString()));
  276. }
  277. bool removeKey = _channelRequest.TryRemove(key, out currReq);
  278. if (!removeKey && appSwitch.TraceError)
  279. {
  280. Trace.WriteLine(string.Format("DateTime {0} Unable to remove web request from dictionary in TerminatePendingWebRequest for channel= {1}", DateTime.Now.ToString(), key));
  281. }
  282. }
  283. }
  284. }
  285. }
  286. ~PubnubBase()
  287. {
  288. //detach
  289. SystemEvents.PowerModeChanged -= new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
  290. }
  291. /**
  292. * PubNub 3.0 API
  293. *
  294. * Prepare Pubnub messaging class initial state
  295. *
  296. * @param string pubish_key.
  297. * @param string subscribe_key.
  298. * @param string secret_key.
  299. * @param bool ssl_on
  300. */
  301. public PubnubBase(string publish_key, string subscribe_key, string secret_key, string cipher_key, bool ssl_on)
  302. {
  303. this.init(publish_key, subscribe_key, secret_key, cipher_key, ssl_on);
  304. }
  305. /**
  306. * PubNub 2.0 Compatibility
  307. *
  308. * Prepare Pubnub messaging class initial state
  309. *
  310. * @param string pubish_key.
  311. * @param string subscribe_key.
  312. */
  313. public PubnubBase(string publish_key, string subscribe_key)
  314. {
  315. this.init(publish_key, subscribe_key, "", "", false);
  316. }
  317. /**
  318. * PubNub 3.0 without SSL
  319. *
  320. * Prepare Pubnub messaging class initial state
  321. *
  322. * @param string pubish_key.
  323. * @param string subscribe_key.
  324. * @param string secret_key.
  325. */
  326. public PubnubBase(string publish_key, string subscribe_key, string secret_key)
  327. {
  328. this.init(publish_key, subscribe_key, secret_key, "", false);
  329. }
  330. /**
  331. * History
  332. *
  333. * Load history from a channel
  334. *
  335. * @param String channel name.
  336. * @param int limit history count response
  337. * @return ListArray of history
  338. */
  339. [Obsolete("This method should no longer be used, please use detailedHistory() instead.")]
  340. public bool history(string channel, int limit)
  341. {
  342. List<string> url = new List<string>();
  343. url.Add("history");
  344. url.Add(this.SUBSCRIBE_KEY);
  345. url.Add(channel);
  346. url.Add("0");
  347. url.Add(limit.ToString());
  348. return _request(url, ResponseType.History);
  349. }
  350. /**
  351. * Detailed History
  352. */
  353. public bool detailedHistory(string channel, long start, long end, int count, bool reverse, Action<object> usercallback)
  354. {
  355. return detailedHistory<object>(channel, start, end, count, reverse, usercallback);
  356. }
  357. public bool detailedHistory<T>(string channel, long start, long end, int count, bool reverse, Action<T> usercallback)
  358. {
  359. if (string.IsNullOrWhiteSpace(channel))
  360. {
  361. throw new ArgumentException("Missing Channel");
  362. }
  363. parameters = "";
  364. if (count <= -1) count = 100;
  365. parameters = "?count=" + count;
  366. if (reverse)
  367. parameters = parameters + "&" + "reverse=" + reverse.ToString().ToLower();
  368. if (start != -1)
  369. parameters = parameters + "&" + "start=" + start.ToString().ToLower();
  370. if (end != -1)
  371. parameters = parameters + "&" + "end=" + end.ToString().ToLower();
  372. List<string> url = new List<string>();
  373. url.Add("v2");
  374. url.Add("history");
  375. url.Add("sub-key");
  376. url.Add(this.SUBSCRIBE_KEY);
  377. url.Add("channel");
  378. url.Add(channel);
  379. return _urlRequest<T>(url, ResponseType.DetailedHistory, usercallback, false);
  380. }
  381. public bool detailedHistory(string channel, long start, Action<object> usercallback, bool reverse)
  382. {
  383. return detailedHistory<object>(channel, start, -1, -1, reverse, usercallback);
  384. }
  385. public bool detailedHistory<T>(string channel, long start, Action<T> usercallback, bool reverse)
  386. {
  387. return detailedHistory<T>(channel, start, -1, -1, reverse, usercallback);
  388. }
  389. public bool detailedHistory(string channel, int count, Action<object> usercallback)
  390. {
  391. return detailedHistory<object>(channel, -1, -1, count, false, usercallback);
  392. }
  393. public bool detailedHistory<T>(string channel, int count, Action<T> usercallback)
  394. {
  395. return detailedHistory<T>(channel, -1, -1, count, false, usercallback);
  396. }
  397. /**
  398. * Publish
  399. *
  400. * Send a message to a channel
  401. *
  402. * @param String channel name.
  403. * @param List<object> info.
  404. * @return bool false on fail
  405. */
  406. public bool publish(string channel, object message, Action<object> usercallback)
  407. {
  408. return publish<object>(channel, message, usercallback);
  409. }
  410. public bool publish<T>(string channel, object message, Action<T> usercallback)
  411. {
  412. if (string.IsNullOrWhiteSpace(channel) || message == null)
  413. {
  414. throw new ArgumentException("Missing Channel or Message");
  415. }
  416. if (string.IsNullOrWhiteSpace(this.PUBLISH_KEY) || this.PUBLISH_KEY.Length <= 0)
  417. {
  418. throw new MissingFieldException("Invalid publish key");
  419. }
  420. if (usercallback == null)
  421. {
  422. throw new ArgumentException("Missing Callback");
  423. }
  424. string msg = jsonEncodePublishMsg(message);
  425. // Generate String to Sign
  426. string signature = "0";
  427. if (this.SECRET_KEY.Length > 0)
  428. {
  429. StringBuilder string_to_sign = new StringBuilder();
  430. string_to_sign
  431. .Append(this.PUBLISH_KEY)
  432. .Append('/')
  433. .Append(this.SUBSCRIBE_KEY)
  434. .Append('/')
  435. .Append(this.SECRET_KEY)
  436. .Append('/')
  437. .Append(channel)
  438. .Append('/')
  439. .Append(msg); // 1
  440. // Sign Message
  441. signature = md5(string_to_sign.ToString());
  442. }
  443. // Build URL
  444. List<string> url = new List<string>();
  445. url.Add("publish");
  446. url.Add(this.PUBLISH_KEY);
  447. url.Add(this.SUBSCRIBE_KEY);
  448. url.Add(signature);
  449. url.Add(channel);
  450. url.Add("0");
  451. url.Add(msg);
  452. return _urlRequest<T>(url, ResponseType.Publish, usercallback, false);
  453. }
  454. private string jsonEncodePublishMsg(object originalMsg)
  455. {
  456. string msg = SerializeToJsonString(originalMsg);
  457. if (this.CIPHER_KEY.Length > 0)
  458. {
  459. PubnubCrypto aes = new PubnubCrypto(this.CIPHER_KEY);
  460. string encryptMsg = aes.encrypt(msg);
  461. msg = SerializeToJsonString(encryptMsg);
  462. }
  463. return msg;
  464. }
  465. private List<object> decodeMsg(List<object> message, ResponseType type)
  466. {
  467. List<object> receivedMsg = new List<object>();
  468. if (type == ResponseType.Presence || type == ResponseType.Publish || type == ResponseType.Time || type == ResponseType.Here_Now || type == ResponseType.Leave)
  469. {
  470. return message;
  471. }
  472. else if (type == ResponseType.DetailedHistory)
  473. {
  474. receivedMsg = decodeDecryptLoop(message);
  475. }
  476. else
  477. {
  478. receivedMsg = decodeDecryptLoop(message);
  479. }
  480. return receivedMsg;
  481. }
  482. private List<object> decodeDecryptLoop(List<object> message)
  483. {
  484. List<object> returnMsg = new List<object>();
  485. if (this.CIPHER_KEY.Length > 0)
  486. {
  487. PubnubCrypto aes = new PubnubCrypto(this.CIPHER_KEY);
  488. var myObjectArray = (from item in message select item as object).ToArray();
  489. IEnumerable enumerable = myObjectArray[0] as IEnumerable;
  490. if (enumerable != null)
  491. {
  492. List<object> receivedMsg = new List<object>();
  493. foreach (object element in enumerable)
  494. {
  495. string decryptMsg = aes.decrypt(element.ToString());
  496. object decodeMsg = JsonConvert.DeserializeObject<object>(decryptMsg);
  497. receivedMsg.Add(decodeMsg);
  498. }
  499. returnMsg.Add(receivedMsg);
  500. }
  501. for (int index = 1; index < myObjectArray.Length; index++)
  502. {
  503. returnMsg.Add(myObjectArray[index]);
  504. }
  505. return returnMsg;
  506. }
  507. else
  508. {
  509. var myObjectArray = (from item in message select item as object).ToArray();
  510. IEnumerable enumerable = myObjectArray[0] as IEnumerable;
  511. if (enumerable != null)
  512. {
  513. List<object> receivedMsg = new List<object>();
  514. foreach (object element in enumerable)
  515. {
  516. receivedMsg.Add(element);
  517. }
  518. returnMsg.Add(receivedMsg);
  519. }
  520. for (int index = 1; index < myObjectArray.Length; index++)
  521. {
  522. returnMsg.Add(myObjectArray[index]);
  523. }
  524. return returnMsg;
  525. }
  526. }
  527. /**
  528. * Subscribe
  529. *
  530. * Listen for a message on a channel (BLOCKING)
  531. *
  532. * @param String channel name.
  533. * @param Procedure function callback
  534. */
  535. public void subscribe(string channel, Action<object> usercallback)
  536. {
  537. subscribe<object>(channel, usercallback);
  538. }
  539. public void subscribe<T>(string channel, Action<T> usercallback)
  540. {
  541. if (string.IsNullOrWhiteSpace(channel))
  542. {
  543. throw new ArgumentException("Missing Channel");
  544. }
  545. if (usercallback == null)
  546. {
  547. throw new ArgumentException("Missing Callback");
  548. }
  549. if (appSwitch.TraceInfo)
  550. {
  551. Trace.WriteLine(string.Format("DateTime {0}, requested subscribe for channel={1}", DateTime.Now.ToString(), channel));
  552. }
  553. if (_channelSubscription.ContainsKey(channel))
  554. {
  555. List<object> result = new List<object>();
  556. string jsonString = "[0, \"Already subscribed\"]";
  557. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  558. result.Add(channel);
  559. if (appSwitch.TraceInfo)
  560. {
  561. Trace.WriteLine(string.Format("DateTime {0}, JSON subscribe response={1}", DateTime.Now.ToString(), jsonString));
  562. }
  563. goToUserCallback<T>(result, usercallback);
  564. }
  565. else
  566. {
  567. _channelSubscription.GetOrAdd(channel, 0);
  568. resetInternetCheckSettings(channel);
  569. _subscribe<T>(channel, 0, usercallback, false);
  570. }
  571. }
  572. private void resetInternetCheckSettings(string channel)
  573. {
  574. if (_channelInternetStatus.ContainsKey(channel))
  575. {
  576. _channelInternetStatus.AddOrUpdate(channel, true, (key, oldValue) => true);
  577. }
  578. else
  579. {
  580. _channelInternetStatus.GetOrAdd(channel, true); //Set to true for internet connection
  581. }
  582. if (_channelInternetRetry.ContainsKey(channel))
  583. {
  584. _channelInternetRetry.AddOrUpdate(channel, 0, (key, oldValue) => 0);
  585. }
  586. else
  587. {
  588. _channelInternetRetry.GetOrAdd(channel, 0); //Initialize the internet retry count
  589. }
  590. }
  591. void OnPubnubWebRequestTimeout(object state, bool timeout)
  592. {
  593. if (timeout)
  594. {
  595. RequestState currentState = state as RequestState;
  596. if (currentState != null)
  597. {
  598. HttpWebRequest request = currentState.request;
  599. if (request != null)
  600. {
  601. if (appSwitch.TraceInfo)
  602. {
  603. Trace.WriteLine(string.Format("DateTime: {0}, OnPubnubWebRequestTimeout: client request timeout reached.Request aborted for channel = {1}", DateTime.Now.ToString(), currentState.channel));
  604. }
  605. request.Abort();
  606. }
  607. }
  608. else
  609. {
  610. if (appSwitch.TraceError)
  611. {
  612. Trace.WriteLine(string.Format("DateTime: {0}, OnPubnubWebRequestTimeout: client request timeout reached. However state is unknown", DateTime.Now.ToString()));
  613. }
  614. }
  615. if (_overrideTcpKeepAlive)
  616. {
  617. //reset heart beat time because http request already timedout
  618. heartBeatTimer.Change(
  619. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000,
  620. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  621. if (appSwitch.TraceInfo)
  622. {
  623. Trace.WriteLine(string.Format("DateTime: {0}, OnPubnubWebRequestTimeout: resetting the heartbeat timeout", DateTime.Now.ToString()));
  624. }
  625. }
  626. }
  627. }
  628. void OnPubnubHeartBeatTimeoutCallback(Object heartbeatState)
  629. {
  630. if (appSwitch.TraceVerbose)
  631. {
  632. Trace.WriteLine(string.Format("DateTime: {0}, **OnPubnubHeartBeatTimeoutCallback**", DateTime.Now.ToString()));
  633. }
  634. RequestState currentState = heartbeatState as RequestState;
  635. if (currentState != null)
  636. {
  637. bool networkConnection = ClientNetworkStatus.checkInternetStatus(_pubnetSystemActive);
  638. if (_channelInternetStatus.ContainsKey(currentState.channel)
  639. && (currentState.type == ResponseType.Subscribe || currentState.type == ResponseType.Presence)
  640. && _overrideTcpKeepAlive)
  641. {
  642. _channelInternetStatus[currentState.channel] = networkConnection;
  643. if (appSwitch.TraceVerbose)
  644. {
  645. Trace.WriteLine(string.Format("DateTime: {0}, OnPubnubHeartBeatTimeoutCallback - Internet connection = {1}", DateTime.Now.ToString(), networkConnection));
  646. }
  647. if (!networkConnection)
  648. {
  649. TerminatePendingWebRequest(currentState);
  650. }
  651. }
  652. }
  653. }
  654. /// <summary>
  655. /// Check the response of the REST API and call for re-subscribe
  656. /// </summary>
  657. /// <typeparam name="T"></typeparam>
  658. /// <param name="subscribeResult"></param>
  659. /// <param name="usercallback"></param>
  660. private void subscribeInternalCallback<T>(object subscribeResult, Action<T> usercallback)
  661. {
  662. List<object> message = subscribeResult as List<object>;
  663. string channelName = "";
  664. if (message != null && message.Count >= 3)
  665. {
  666. channelName = message[2].ToString();
  667. }
  668. else
  669. {
  670. if (appSwitch.TraceError)
  671. {
  672. Trace.WriteLine(string.Format("DateTime {0}, Lost Channel Name for resubscribe", DateTime.Now.ToString()));
  673. }
  674. return;
  675. }
  676. if (!_channelSubscription.ContainsKey(channelName))
  677. {
  678. if (appSwitch.TraceInfo)
  679. {
  680. Trace.WriteLine(string.Format("DateTime {0}, Due to Unsubscribe, further re-subscription was stopped for channel {1}", DateTime.Now.ToString(), channelName.ToString()));
  681. }
  682. return;
  683. }
  684. if (message != null && message.Count >= 3)
  685. {
  686. _subscribe<T>(channelName, (object)message[1], usercallback, false);
  687. }
  688. }
  689. private void presenceInternalCallback<T>(object presenceResult, Action<T> usercallback)
  690. {
  691. List<object> message = presenceResult as List<object>;
  692. string channelName = "";
  693. if (message != null && message.Count >= 3)
  694. {
  695. channelName = message[2].ToString();
  696. }
  697. else
  698. {
  699. if (appSwitch.TraceError)
  700. {
  701. Trace.WriteLine(string.Format("DateTime {0}, Lost Channel Name for re-presence", DateTime.Now.ToString()));
  702. }
  703. return;
  704. }
  705. if (message != null && message.Count >= 3)
  706. {
  707. _presence<T>(channelName, (object)message[1], usercallback, false);
  708. }
  709. }
  710. /// <summary>
  711. /// To unsubscribe a channel
  712. /// </summary>
  713. /// <param name="channel"></param>
  714. /// <param name="usercallback"></param>
  715. public void unsubscribe(string channel, Action<object> usercallback)
  716. {
  717. unsubscribe<object>(channel, usercallback);
  718. }
  719. /// <summary>
  720. /// To unsubscribe a channel
  721. /// </summary>
  722. /// <typeparam name="T"></typeparam>
  723. /// <param name="channel"></param>
  724. /// <param name="usercallback"></param>
  725. public void unsubscribe<T>(string channel, Action<T> usercallback)
  726. {
  727. if (string.IsNullOrWhiteSpace(channel))
  728. {
  729. throw new ArgumentException("Missing Channel");
  730. }
  731. bool unsubStatus = false;
  732. if (appSwitch.TraceInfo)
  733. {
  734. Trace.WriteLine(string.Format("DateTime {0}, requested unsubscribe for channel={1}", DateTime.Now.ToString(), channel));
  735. }
  736. string jsonString = "";
  737. List<object> result = new List<object>();
  738. if (_channelSubscription.ContainsKey(channel))
  739. {
  740. if (_channelRequest.ContainsKey(channel))
  741. {
  742. long unsubValue;
  743. unsubStatus = _channelSubscription.TryRemove(channel, out unsubValue);
  744. if (unsubStatus)
  745. {
  746. jsonString = string.Format("[1, \"Unsubscribed from {0}\"]", channel);
  747. }
  748. else
  749. {
  750. jsonString = string.Format("[1, \"Error unsubscribing from {0}\"]", channel);
  751. }
  752. HttpWebRequest storedRequest = _channelRequest[channel].request;
  753. storedRequest.Abort();
  754. }
  755. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  756. result.Add(channel);
  757. if (appSwitch.TraceInfo)
  758. {
  759. Trace.WriteLine(string.Format("DateTime {0}, JSON unsubscribe response={1}", DateTime.Now.ToString(), jsonString));
  760. }
  761. goToUserCallback<T>(result, usercallback);
  762. //just fire leave() event to REST API for safeguard
  763. List<string> url = new List<string>();
  764. url.Add("v2");
  765. url.Add("presence");
  766. url.Add("sub_key");
  767. url.Add(this.SUBSCRIBE_KEY);
  768. url.Add("channel");
  769. url.Add(channel);
  770. url.Add("leave");
  771. _urlRequest<T>(url, ResponseType.Leave, null, false);
  772. }
  773. else
  774. {
  775. result = new List<object>();
  776. jsonString = "[0, \"Channel Not Subscribed\"]";
  777. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  778. result.Add(channel);
  779. if (appSwitch.TraceInfo)
  780. {
  781. Trace.WriteLine(string.Format("DateTime {0}, JSON unsubscribe response={1}", DateTime.Now.ToString(), jsonString));
  782. }
  783. goToUserCallback<T>(result, usercallback);
  784. }
  785. }
  786. /**
  787. * Subscribe - Private Interface
  788. *
  789. * @param String channel name.
  790. * @param Procedure function callback
  791. * @param String timetoken.
  792. */
  793. private void _subscribe<T>(string channel, object timetoken, Action<T> usercallback, bool reconnect)
  794. {
  795. //Exit if the channel is unsubscribed
  796. if (!_channelSubscription.ContainsKey(channel))
  797. {
  798. if (appSwitch.TraceInfo)
  799. {
  800. Trace.WriteLine(string.Format("DateTime {0}, Due to Unsubscribe, further subscription was stopped for channel {1}", DateTime.Now.ToString(), channel.ToString()));
  801. }
  802. return;
  803. }
  804. _channelSubscription.AddOrUpdate(channel, Convert.ToInt64(timetoken.ToString()), (key, oldValue) => Convert.ToInt64(timetoken.ToString())); //Store the timetoken
  805. if (_channelInternetStatus.ContainsKey(channel) && (!_channelInternetStatus[channel]) && _pubnetSystemActive)
  806. {
  807. if (_channelInternetRetry.ContainsKey(channel) && (_channelInternetRetry[channel] >= PUBNUB_NETWORK_CHECK_RETRIES))
  808. {
  809. if (appSwitch.TraceInfo)
  810. {
  811. Trace.WriteLine(string.Format("DateTime {0}, Subscribe channel={1} - No internet connection. MAXed retries for internet ", DateTime.Now.ToString(), channel));
  812. }
  813. subscribeExceptionHandler<T>(channel, usercallback, true);
  814. return;
  815. }
  816. if (_overrideTcpKeepAlive)
  817. {
  818. if (appSwitch.TraceInfo)
  819. {
  820. Trace.WriteLine(string.Format("DateTime {0}, Subscribe - No internet connection for {1}", DateTime.Now.ToString(), channel));
  821. }
  822. ReconnectState<T> netState = new ReconnectState<T>();
  823. netState.channel = channel;
  824. netState.type = ResponseType.Subscribe;
  825. netState.callback = usercallback;
  826. netState.timetoken = timetoken;
  827. reconnectNetwork<T>(netState);
  828. return;
  829. }
  830. }
  831. // Begin recursive subscribe
  832. try
  833. {
  834. // Build URL
  835. List<string> url = new List<string>();
  836. url.Add("subscribe");
  837. url.Add(this.SUBSCRIBE_KEY);
  838. url.Add(channel);
  839. url.Add("0");
  840. url.Add(timetoken.ToString());
  841. // Wait for message
  842. _urlRequest<T>(url, ResponseType.Subscribe, usercallback, reconnect);
  843. }
  844. catch (Exception ex)
  845. {
  846. if (appSwitch.TraceError)
  847. {
  848. Trace.WriteLine(string.Format("DateTime {0} method:_subscribe \n channel={1} \n timetoken={2} \n Exception Details={3}", DateTime.Now.ToString(), channel, timetoken.ToString(), ex.ToString()));
  849. }
  850. this._subscribe<T>(channel, timetoken, usercallback, false);
  851. }
  852. }
  853. /**
  854. * Presence feature
  855. *
  856. * Listen for a presence message on a channel (BLOCKING)
  857. *
  858. * @param String channel name. (+"pnpres")
  859. * @param Procedure function callback
  860. */
  861. public void presence(string channel, Action<object> usercallback)
  862. {
  863. presence<object>(channel, usercallback);
  864. }
  865. public void presence<T>(string channel, Action<T> usercallback)
  866. {
  867. if (string.IsNullOrWhiteSpace(channel))
  868. {
  869. throw new ArgumentException("Missing Channel");
  870. }
  871. if (usercallback == null)
  872. {
  873. throw new ArgumentException("Missing Callback");
  874. }
  875. channel = string.Format("{0}-pnpres", channel);
  876. if (appSwitch.TraceInfo)
  877. {
  878. Trace.WriteLine(string.Format("DateTime {0}, requested presence for channel={1}", DateTime.Now.ToString(), channel));
  879. }
  880. if (_channelPresence.ContainsKey(channel))
  881. {
  882. List<object> result = new List<object>();
  883. string jsonString = "[0, \"Presence Already subscribed\"]";
  884. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  885. result.Add(channel.Replace("-pnpres", ""));
  886. if (appSwitch.TraceInfo)
  887. {
  888. Trace.WriteLine(string.Format("DateTime {0}, JSON presence response={1}", DateTime.Now.ToString(), jsonString));
  889. }
  890. goToUserCallback<T>(result, usercallback);
  891. }
  892. else
  893. {
  894. _channelPresence.GetOrAdd(channel, 0);
  895. resetInternetCheckSettings(channel);
  896. this._presence<T>(channel, 0, usercallback, false);
  897. }
  898. }
  899. /**
  900. * Presence feature - Private Interface
  901. *
  902. * @param String channel name.
  903. * @param Procedure function callback
  904. * @param String timetoken.
  905. */
  906. private void _presence<T>(string channel, object timetoken, Action<T> usercallback, bool reconnect)
  907. {
  908. //Exit if the channel is unsubscribed
  909. if (!_channelPresence.ContainsKey(channel))
  910. {
  911. if (appSwitch.TraceInfo)
  912. {
  913. Trace.WriteLine(string.Format("DateTime {0}, Due to Presence-unsubscribe, further presence was stopped for channel {1}", DateTime.Now.ToString(), channel.ToString()));
  914. }
  915. return;
  916. }
  917. _channelPresence.AddOrUpdate(channel, Convert.ToInt64(timetoken.ToString()), (key, oldValue) => Convert.ToInt64(timetoken.ToString())); //Store the timetoken
  918. if (_channelInternetStatus.ContainsKey(channel) && (!_channelInternetStatus[channel]) && _pubnetSystemActive)
  919. {
  920. if (_channelInternetRetry.ContainsKey(channel) && (_channelInternetRetry[channel] >= PUBNUB_NETWORK_CHECK_RETRIES))
  921. {
  922. if (appSwitch.TraceInfo)
  923. {
  924. Trace.WriteLine(string.Format("DateTime {0}, Presence channel={1} - No internet connection. MAXed retries for internet ", DateTime.Now.ToString(), channel));
  925. }
  926. presenceExceptionHandler<T>(channel, usercallback, true);
  927. return;
  928. }
  929. if (_overrideTcpKeepAlive)
  930. {
  931. if (appSwitch.TraceInfo)
  932. {
  933. Trace.WriteLine(string.Format("DateTime {0}, Presence - No internet connection for {1}", DateTime.Now.ToString(), channel));
  934. }
  935. ReconnectState<T> netState = new ReconnectState<T>();
  936. netState.channel = channel;
  937. netState.type = ResponseType.Presence;
  938. netState.callback = usercallback;
  939. netState.timetoken = timetoken;
  940. reconnectNetwork<T>(netState);
  941. return;
  942. }
  943. }
  944. // Begin recursive subscribe
  945. try
  946. {
  947. // Build URL
  948. List<string> url = new List<string>();
  949. url.Add("subscribe");
  950. url.Add(this.SUBSCRIBE_KEY);
  951. url.Add(channel);
  952. url.Add("0");
  953. url.Add(timetoken.ToString());
  954. // Wait for message
  955. _urlRequest<T>(url, ResponseType.Presence, usercallback, reconnect);
  956. }
  957. catch (Exception ex)
  958. {
  959. if (appSwitch.TraceError)
  960. {
  961. Trace.WriteLine(string.Format("method:_presence \n channel={0} \n timetoken={1} \n Exception Details={2}", channel, timetoken.ToString(), ex.ToString()));
  962. }
  963. this._presence<T>(channel, timetoken, usercallback, false);
  964. }
  965. }
  966. public void presence_unsubscribe(string channel, Action<object> usercallback)
  967. {
  968. presence_unsubscribe<object>(channel, usercallback);
  969. }
  970. public void presence_unsubscribe<T>(string channel, Action<T> usercallback)
  971. {
  972. if (string.IsNullOrWhiteSpace(channel))
  973. {
  974. throw new ArgumentException("Missing Channel");
  975. }
  976. channel = string.Format("{0}-pnpres", channel);
  977. bool unsubStatus = false;
  978. if (appSwitch.TraceInfo)
  979. {
  980. Trace.WriteLine(string.Format("DateTime {0}, requested presence-unsubscribe for channel={1}", DateTime.Now.ToString(), channel));
  981. }
  982. string jsonString = "";
  983. List<object> result = new List<object>();
  984. if (_channelPresence.ContainsKey(channel))
  985. {
  986. if (_channelRequest.ContainsKey(channel))
  987. {
  988. long unsubPreValue;
  989. unsubStatus = _channelPresence.TryRemove(channel, out unsubPreValue);
  990. if (unsubStatus)
  991. {
  992. jsonString = string.Format("[1, \"Presence-Unsubscribed from {0}\"]", channel.Replace("-pnpres", ""));
  993. }
  994. else
  995. {
  996. jsonString = string.Format("[1, \"Error presence-unsubscribing from {0}\"]", channel.Replace("-pnpres", ""));
  997. }
  998. HttpWebRequest storedRequest = _channelRequest[channel].request;
  999. storedRequest.Abort();
  1000. }
  1001. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1002. result.Add(channel.Replace("-pnpres", ""));
  1003. if (appSwitch.TraceInfo)
  1004. {
  1005. Trace.WriteLine(string.Format("DateTime {0}, JSON presence-unsubscribe response={1}", DateTime.Now.ToString(), jsonString));
  1006. }
  1007. goToUserCallback<T>(result, usercallback);
  1008. }
  1009. else
  1010. {
  1011. result = new List<object>();
  1012. jsonString = "[0, \"Channel Not Subscribed\"]";
  1013. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1014. result.Add(channel.Replace("-pnpres", ""));
  1015. if (appSwitch.TraceInfo)
  1016. {
  1017. Trace.WriteLine(string.Format("DateTime {0}, JSON presence-unsubscribe response={1}", DateTime.Now.ToString(), jsonString));
  1018. }
  1019. goToUserCallback<T>(result, usercallback);
  1020. }
  1021. }
  1022. public bool here_now(string channel, Action<object> usercallback)
  1023. {
  1024. return here_now<object>(channel, usercallback);
  1025. }
  1026. public bool here_now<T>(string channel, Action<T> usercallback)
  1027. {
  1028. if (string.IsNullOrWhiteSpace(channel))
  1029. {
  1030. throw new ArgumentException("Missing Channel");
  1031. }
  1032. List<string> url = new List<string>();
  1033. url.Add("v2");
  1034. url.Add("presence");
  1035. url.Add("sub_key");
  1036. url.Add(this.SUBSCRIBE_KEY);
  1037. url.Add("channel");
  1038. url.Add(channel);
  1039. return _urlRequest<T>(url, ResponseType.Here_Now, usercallback, false);
  1040. }
  1041. /**
  1042. * Time
  1043. *
  1044. * Timestamp from PubNub Cloud
  1045. *
  1046. * @return object timestamp.
  1047. */
  1048. public bool time(Action<object> usercallback)
  1049. {
  1050. return time<object>(usercallback);
  1051. }
  1052. public bool time<T>(Action<T> usercallback)
  1053. {
  1054. List<string> url = new List<string>();
  1055. url.Add("time");
  1056. url.Add("0");
  1057. return _urlRequest<T>(url, ResponseType.Time, usercallback, false);
  1058. }
  1059. /**
  1060. * Http Get Request
  1061. *
  1062. * @param List<string> request of URL directories.
  1063. * @return List<object> from JSON response.
  1064. */
  1065. private bool _request(List<string> url_components, ResponseType type)
  1066. {
  1067. List<object> result = new List<object>();
  1068. StringBuilder url = new StringBuilder();
  1069. // Add Origin To The Request
  1070. url.Append(this.ORIGIN);
  1071. // Generate URL with UTF-8 Encoding
  1072. foreach (string url_bit in url_components)
  1073. {
  1074. url.Append("/");
  1075. url.Append(_encodeURIcomponent(url_bit, type));
  1076. }
  1077. if (type == ResponseType.Presence || type == ResponseType.Subscribe)
  1078. {
  1079. url.Append("?uuid=");
  1080. url.Append(this.sessionUUID);
  1081. }
  1082. if (type == ResponseType.DetailedHistory)
  1083. url.Append(parameters);
  1084. // Temporary fail if string too long
  1085. if (url.Length > this.LIMIT)
  1086. {
  1087. result.Add(0);
  1088. result.Add("Message Too Long.");
  1089. // return result;
  1090. }
  1091. Uri requestUri = new Uri(url.ToString());
  1092. // Force canonical path and query
  1093. string paq = requestUri.PathAndQuery;
  1094. FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
  1095. ulong flags = (ulong)flagsFieldInfo.GetValue(requestUri);
  1096. flags &= ~((ulong)0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  1097. flagsFieldInfo.SetValue(requestUri, flags);
  1098. // Create Request
  1099. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
  1100. try
  1101. {
  1102. // Make request with the following inline Asynchronous callback
  1103. IAsyncResult asyncResult = request.BeginGetResponse(new AsyncCallback((asynchronousResult) =>
  1104. {
  1105. HttpWebRequest aRequest = (HttpWebRequest)asynchronousResult.AsyncState;
  1106. HttpWebResponse aResponse = (HttpWebResponse)aRequest.EndGetResponse(asynchronousResult);
  1107. using (StreamReader streamReader = new StreamReader(aResponse.GetResponseStream()))
  1108. {
  1109. // Deserialize the result
  1110. string jsonString = streamReader.ReadToEnd();
  1111. result = WrapResultBasedOnResponseType(type, jsonString, url_components, false);
  1112. }
  1113. }), request
  1114. );
  1115. return true;
  1116. }
  1117. catch (System.Exception ex)
  1118. {
  1119. Console.WriteLine(ex.ToString());
  1120. return false;
  1121. }
  1122. }
  1123. /**
  1124. * Http Get Request
  1125. *
  1126. * @param List<string> request of URL directories.
  1127. * @return List<object> from JSON response.
  1128. */
  1129. private bool _urlRequest<T>(List<string> url_components, ResponseType type, Action<T> usercallback, bool reconnect)
  1130. {
  1131. List<object> result = new List<object>();
  1132. string channelName = getChannelName(url_components, type);
  1133. StringBuilder url = new StringBuilder();
  1134. // Add Origin To The Request
  1135. url.Append(this.ORIGIN);
  1136. // Generate URL with UTF-8 Encoding
  1137. foreach (string url_bit in url_components)
  1138. {
  1139. url.Append("/");
  1140. url.Append(_encodeURIcomponent(url_bit, type));
  1141. }
  1142. if (type == ResponseType.Presence || type == ResponseType.Subscribe || type == ResponseType.Leave)
  1143. {
  1144. url.Append("?uuid=");
  1145. url.Append(this.sessionUUID);
  1146. }
  1147. if (type == ResponseType.DetailedHistory)
  1148. url.Append(parameters);
  1149. // Temporary fail if string too long
  1150. if (url.Length > this.LIMIT)
  1151. {
  1152. result.Add(0);
  1153. result.Add("Message Too Long.");
  1154. // return result;
  1155. }
  1156. Uri requestUri = new Uri(url.ToString());
  1157. if ((type == ResponseType.Publish || type == ResponseType.Subscribe || type == ResponseType.Presence)
  1158. && (!IsRunningOnMono()))
  1159. {
  1160. // Force canonical path and query
  1161. string paq = requestUri.PathAndQuery;
  1162. FieldInfo flagsFieldInfo = typeof(Uri).GetField("m_Flags", BindingFlags.Instance | BindingFlags.NonPublic);
  1163. ulong flags = (ulong)flagsFieldInfo.GetValue(requestUri);
  1164. flags &= ~((ulong)0x30); // Flags.PathNotCanonical|Flags.QueryNotCanonical
  1165. flagsFieldInfo.SetValue(requestUri, flags);
  1166. }
  1167. try
  1168. {
  1169. // Create Request
  1170. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUri);
  1171. request.Timeout = PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC * 1000;
  1172. if ((!_channelSubscription.ContainsKey(channelName) && type == ResponseType.Subscribe)
  1173. || (!_channelPresence.ContainsKey(channelName) && type == ResponseType.Presence))
  1174. {
  1175. if (appSwitch.TraceInfo)
  1176. {
  1177. Trace.WriteLine(string.Format("DateTime {0}, Due to Unsubscribe, request aborted for channel={1}", DateTime.Now.ToString(), channelName));
  1178. }
  1179. request.Abort();
  1180. }
  1181. RequestState pubnubRequestState = new RequestState();
  1182. pubnubRequestState.request = request;
  1183. pubnubRequestState.channel = channelName;
  1184. pubnubRequestState.type = type;
  1185. if (type == ResponseType.Subscribe || type == ResponseType.Presence)
  1186. {
  1187. _channelRequest.AddOrUpdate(channelName, pubnubRequestState, (key, oldState) => pubnubRequestState);
  1188. }
  1189. if (_overrideTcpKeepAlive)
  1190. {
  1191. //Eventhough heart-beat is disabled, run one time to check internet connection by setting dueTime=0
  1192. heartBeatTimer = new System.Threading.Timer(
  1193. new TimerCallback(OnPubnubHeartBeatTimeoutCallback), pubnubRequestState, 0,
  1194. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? Timeout.Infinite : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  1195. }
  1196. {
  1197. //request.ServicePoint.SetTcpKeepAlive(true, PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000, 1000);
  1198. }
  1199. if (appSwitch.TraceInfo)
  1200. {
  1201. Trace.WriteLine(string.Format("DateTime {0}, Request={1}", DateTime.Now.ToString(), requestUri.ToString()));
  1202. }
  1203. // Make request with the following inline Asynchronous callback
  1204. IAsyncResult asyncResult = request.BeginGetResponse(new AsyncCallback((asynchronousResult) =>
  1205. {
  1206. try
  1207. {
  1208. RequestState asynchRequestState = (RequestState)asynchronousResult.AsyncState;
  1209. HttpWebRequest aRequest = (HttpWebRequest)asynchRequestState.request;
  1210. if (aRequest != null)
  1211. {
  1212. using (HttpWebResponse aResponse = (HttpWebResponse)aRequest.EndGetResponse(asynchronousResult))
  1213. {
  1214. pubnubRequestState.response = aResponse;
  1215. using (StreamReader streamReader = new StreamReader(aResponse.GetResponseStream()))
  1216. {
  1217. if (type == ResponseType.Subscribe || type == ResponseType.Presence)
  1218. {
  1219. _channelInternetStatus.AddOrUpdate(channelName, true, (key, oldValue) => true);
  1220. }
  1221. // Deserialize the result
  1222. string jsonString = streamReader.ReadToEnd();
  1223. streamReader.Close();
  1224. if (_overrideTcpKeepAlive)
  1225. {
  1226. heartBeatTimer.Change(
  1227. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000,
  1228. (-1 == PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC) ? -1 : PUBNUB_NETWORK_TCP_CHECK_INTERVAL_IN_SEC * 1000);
  1229. }
  1230. if (appSwitch.TraceInfo)
  1231. {
  1232. Trace.WriteLine(string.Format("DateTime {0}, JSON for channel={1} ({2}) ={3}", DateTime.Now.ToString(), channelName, type.ToString(), jsonString));
  1233. }
  1234. result = WrapResultBasedOnResponseType(type, jsonString, url_components, reconnect);
  1235. }
  1236. aResponse.Close();
  1237. }
  1238. }
  1239. else
  1240. {
  1241. if (appSwitch.TraceInfo)
  1242. {
  1243. Trace.WriteLine(string.Format("DateTime {0}, Request aborted for channel={1}", DateTime.Now.ToString(), channelName));
  1244. }
  1245. }
  1246. if (result != null && result.Count >= 1 && usercallback != null)
  1247. {
  1248. responseToUserCallback<T>(result, type, channelName, usercallback);
  1249. }
  1250. switch (type)
  1251. {
  1252. case ResponseType.Subscribe:
  1253. subscribeInternalCallback<T>(result, usercallback);
  1254. break;
  1255. case ResponseType.Presence:
  1256. presenceInternalCallback<T>(result, usercallback);
  1257. break;
  1258. default:
  1259. break;
  1260. }
  1261. }
  1262. catch (WebException webEx)
  1263. {
  1264. if (appSwitch.TraceError)
  1265. {
  1266. Trace.WriteLine(string.Format("DateTime {0}, WebException: {1} for URL: {2}", DateTime.Now.ToString(), webEx.ToString(), requestUri.ToString()));
  1267. }
  1268. RequestState state = (RequestState)asynchronousResult.AsyncState;
  1269. if (state.response != null)
  1270. {
  1271. state.response.Close();
  1272. state.request.Abort();
  1273. }
  1274. if ((webEx.Status == WebExceptionStatus.NameResolutionFailure //No network
  1275. || webEx.Status == WebExceptionStatus.ConnectFailure //Sending Keep-alive packet failed (No network)/Server is down.
  1276. || webEx.Status == WebExceptionStatus.ServerProtocolViolation//Problem with proxy or ISP
  1277. || webEx.Status == WebExceptionStatus.ProtocolError
  1278. ) && (!_overrideTcpKeepAlive))
  1279. {
  1280. //internet connection problem.
  1281. if (appSwitch.TraceError)
  1282. {
  1283. Trace.WriteLine(string.Format("DateTime {0}, _urlRequest - Internet connection problem", DateTime.Now.ToString()));
  1284. }
  1285. if (_channelInternetStatus.ContainsKey(channelName)
  1286. && (type == ResponseType.Subscribe || type == ResponseType.Presence))
  1287. {
  1288. if (_channelInternetStatus[channelName])
  1289. {
  1290. //Reset Retry if previous state is true
  1291. _channelInternetRetry.AddOrUpdate(channelName, 0, (key, oldValue) => 0);
  1292. }
  1293. else
  1294. {
  1295. _channelInternetRetry.AddOrUpdate(channelName, 1, (key, oldValue) => oldValue + 1);
  1296. if (appSwitch.TraceInfo)
  1297. {
  1298. Trace.WriteLine(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));
  1299. }
  1300. }
  1301. _channelInternetStatus[channelName] = false;
  1302. Thread.Sleep(PUBNUB_WEBREQUEST_RETRY_INTERVAL_IN_SEC * 1000);
  1303. }
  1304. }
  1305. urlRequestCommonExceptionHandler<T>(type, channelName, usercallback);
  1306. }
  1307. catch (Exception ex)
  1308. {
  1309. RequestState state = (RequestState)asynchronousResult.AsyncState;
  1310. if (state.response != null)
  1311. state.response.Close();
  1312. if (appSwitch.TraceError)
  1313. {
  1314. Trace.WriteLine(string.Format("DateTime {0} Exception= {1} for URL: {2}", DateTime.Now.ToString(), ex.ToString(), requestUri.ToString()));
  1315. }
  1316. urlRequestCommonExceptionHandler<T>(type, channelName, usercallback);
  1317. }
  1318. }), pubnubRequestState);
  1319. if (!IsRunningOnMono())
  1320. {
  1321. ThreadPool.RegisterWaitForSingleObject(asyncResult.AsyncWaitHandle, new WaitOrTimerCallback(OnPubnubWebRequestTimeout), pubnubRequestState, PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC * 1000, true);
  1322. }
  1323. else
  1324. {
  1325. if (!asyncResult.AsyncWaitHandle.WaitOne(PUBNUB_WEBREQUEST_CALLBACK_INTERVAL_IN_SEC * 1000))
  1326. {
  1327. OnPubnubWebRequestTimeout(pubnubRequestState, true);
  1328. }
  1329. }
  1330. return true;
  1331. }
  1332. catch (System.Exception ex)
  1333. {
  1334. if (appSwitch.TraceError)
  1335. {
  1336. Trace.WriteLine(string.Format("DateTime {0} Exception={1}", DateTime.Now.ToString(), ex.ToString()));
  1337. }
  1338. urlRequestCommonExceptionHandler<T>(type, channelName, usercallback);
  1339. return false;
  1340. }
  1341. }
  1342. private void urlRequestCommonExceptionHandler<T>(ResponseType type, string channelName, Action<T> usercallback)
  1343. {
  1344. if (type == ResponseType.Subscribe)
  1345. {
  1346. subscribeExceptionHandler<T>(channelName, usercallback, false);
  1347. }
  1348. else if (type == ResponseType.Presence)
  1349. {
  1350. presenceExceptionHandler<T>(channelName, usercallback, false);
  1351. }
  1352. else if (type == ResponseType.Publish)
  1353. {
  1354. publishExceptionHandler<T>(channelName, usercallback);
  1355. }
  1356. else if (type == ResponseType.Here_Now)
  1357. {
  1358. hereNowExceptionHandler<T>(channelName, usercallback);
  1359. }
  1360. else if (type == ResponseType.DetailedHistory)
  1361. {
  1362. detailedHistoryExceptionHandler<T>(channelName, usercallback);
  1363. }
  1364. else if (type == ResponseType.Time)
  1365. {
  1366. timeExceptionHandler<T>(usercallback);
  1367. }
  1368. else if (type == ResponseType.Leave)
  1369. {
  1370. //no action at this time
  1371. }
  1372. }
  1373. private void responseToUserCallback<T>(List<object> result, ResponseType type, string channelName, Action<T> usercallback) //where T: class//, new()
  1374. {
  1375. switch (type)
  1376. {
  1377. case ResponseType.Subscribe:
  1378. var msgs = (from item in result
  1379. select item as object).ToArray();
  1380. if (msgs != null && msgs.Length > 0)
  1381. {
  1382. List<object> msgList = msgs[0] as List<object>;
  1383. if (msgList != null && msgList.Count > 0)
  1384. {
  1385. foreach (object item in msgList)
  1386. {
  1387. List<object> itemMsg = new List<object>();
  1388. itemMsg.Add(item);
  1389. for (int index = 1; index < msgs.Length; index++)
  1390. {
  1391. itemMsg.Add(msgs[index]);
  1392. }
  1393. goToUserCallback<T>(itemMsg, usercallback);
  1394. }
  1395. }
  1396. }
  1397. removeChannelRequest(channelName);
  1398. break;
  1399. case ResponseType.Presence:
  1400. var msgp = (from item in result
  1401. select item as object).ToArray();
  1402. if (msgp != null && msgp.Length > 0)
  1403. {
  1404. JArray msgArr = msgp[0] as JArray;
  1405. if (msgArr != null && msgArr.Count > 0)
  1406. {
  1407. foreach (object item in msgArr)
  1408. {
  1409. List<object> itemMsg = new List<object>();
  1410. itemMsg.Add(item);
  1411. for (int index = 1; index < msgp.Length; index++)
  1412. {
  1413. if (index == 2)
  1414. {
  1415. msgp[index] = ((string)msgp[index]).Replace("-pnpres", "");
  1416. }
  1417. itemMsg.Add(msgp[index]);
  1418. }
  1419. goToUserCallback<T>(itemMsg, usercallback);
  1420. }
  1421. }
  1422. }
  1423. removeChannelRequest(channelName);
  1424. break;
  1425. case ResponseType.Publish:
  1426. if (result != null && result.Count > 0)
  1427. {
  1428. goToUserCallback<T>(result, usercallback);
  1429. }
  1430. break;
  1431. case ResponseType.DetailedHistory:
  1432. if (result != null && result.Count > 0)
  1433. {
  1434. goToUserCallback<T>(result, usercallback);
  1435. }
  1436. break;
  1437. case ResponseType.Here_Now:
  1438. if (result != null && result.Count > 0)
  1439. {
  1440. goToUserCallback<T>(result, usercallback);
  1441. }
  1442. break;
  1443. case ResponseType.Time:
  1444. if (result != null && result.Count > 0)
  1445. {
  1446. goToUserCallback<T>(result, usercallback);
  1447. }
  1448. break;
  1449. case ResponseType.Leave:
  1450. //No response to callback
  1451. break;
  1452. default:
  1453. break;
  1454. }
  1455. }
  1456. private void jsonResponseToUserCallback<T>(List<object> result, Action<T> usercallback)
  1457. {
  1458. string usercallbackJSON = "";
  1459. if (typeof(T) == typeof(string))
  1460. {
  1461. usercallbackJSON = JsonConvert.SerializeObject(result);
  1462. Action<string> castUserCallback = usercallback as Action<string>;
  1463. castUserCallback(usercallbackJSON);
  1464. }
  1465. }
  1466. private void removeChannelRequest(string channelName)
  1467. {
  1468. if (_channelRequest.ContainsKey(channelName))
  1469. {
  1470. RequestState currentReq = _channelRequest[channelName];
  1471. currentReq.request = null;
  1472. currentReq.response = null;
  1473. bool remove = _channelRequest.TryRemove(channelName, out currentReq);
  1474. if (!remove && appSwitch.TraceError)
  1475. {
  1476. Trace.WriteLine(string.Format("DateTime {0} Unable to remove request from dictionary for channel ={1}", DateTime.Now.ToString(), channelName));
  1477. }
  1478. }
  1479. }
  1480. private void subscribeExceptionHandler<T>(string channelName, Action<T> usercallback, bool reconnectTried)
  1481. {
  1482. if (reconnectTried)
  1483. {
  1484. if (appSwitch.TraceInfo)
  1485. {
  1486. Trace.WriteLine(string.Format("DateTime {0}, MAX retries reached. Exiting the subscribe for channel = {1}", DateTime.Now.ToString(), channelName));
  1487. }
  1488. unsubscribe(channelName, null);
  1489. List<object> errorResult = new List<object>();
  1490. string jsonString = string.Format("[0, \"Unsubscribed after {0} failed retries\"]", PUBNUB_NETWORK_CHECK_RETRIES);
  1491. errorResult = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1492. errorResult.Add(channelName);
  1493. if (appSwitch.TraceInfo)
  1494. {
  1495. Trace.WriteLine(string.Format("DateTime {0}, Subscribe JSON network error response={1}", DateTime.Now.ToString(), jsonString));
  1496. }
  1497. if (usercallback != null)
  1498. {
  1499. goToUserCallback<T>(errorResult, usercallback);
  1500. }
  1501. }
  1502. else
  1503. {
  1504. List<object> result = new List<object>();
  1505. result.Add("0");
  1506. if (_subscribeMsg.ContainsKey(channelName))
  1507. {
  1508. List<object> lastResult = _subscribeMsg[channelName] as List<object>;
  1509. result.Add((lastResult != null) ? lastResult[1] : "0"); //get last timetoken
  1510. }
  1511. else
  1512. {
  1513. result.Add("0"); //timetoken
  1514. }
  1515. result.Add(channelName); //send channel name
  1516. subscribeInternalCallback<T>(result, usercallback);
  1517. }
  1518. }
  1519. private void presenceExceptionHandler<T>(string channelName, Action<T> usercallback, bool reconnectTry)
  1520. {
  1521. if (reconnectTry)
  1522. {
  1523. if (appSwitch.TraceInfo)
  1524. {
  1525. Trace.WriteLine(string.Format("DateTime {0}, MAX retries reached. Exiting the presence for channel = {1}", DateTime.Now.ToString(), channelName));
  1526. }
  1527. presence_unsubscribe(channelName.Replace("-pnpres", ""), null);
  1528. List<object> errorResult = new List<object>();
  1529. string jsonString = string.Format("[0, \"Presence-unsubscribed after {0} failed retries\"]", PUBNUB_NETWORK_CHECK_RETRIES);
  1530. errorResult = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1531. errorResult.Add(channelName);
  1532. if (appSwitch.TraceInfo)
  1533. {
  1534. Trace.WriteLine(string.Format("DateTime {0}, Presence JSON network error response={1}", DateTime.Now.ToString(), jsonString));
  1535. }
  1536. if (usercallback != null)
  1537. {
  1538. goToUserCallback<T>(errorResult, usercallback);
  1539. }
  1540. }
  1541. else
  1542. {
  1543. List<object> result = new List<object>();
  1544. result.Add("0");
  1545. if (_presenceMsg.ContainsKey(channelName))
  1546. {
  1547. List<object> lastResult = _presenceMsg[channelName] as List<object>;
  1548. result.Add((lastResult != null) ? lastResult[1] : "0"); //get last timetoken
  1549. }
  1550. else
  1551. {
  1552. result.Add("0"); //timetoken
  1553. }
  1554. result.Add(channelName); //send channel name
  1555. presenceInternalCallback<T>(result, usercallback);
  1556. }
  1557. }
  1558. private void publishExceptionHandler<T>(string channelName, Action<T> usercallback)
  1559. {
  1560. List<object> result = new List<object>();
  1561. string jsonString = "[0, \"Network connnect error\"]";
  1562. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1563. result.Add(channelName);
  1564. if (appSwitch.TraceInfo)
  1565. {
  1566. Trace.WriteLine(string.Format("DateTime {0}, JSON publish response={1}", DateTime.Now.ToString(), jsonString));
  1567. }
  1568. goToUserCallback<T>(result, usercallback);
  1569. }
  1570. private void hereNowExceptionHandler<T>(string channelName, Action<T> usercallback)
  1571. {
  1572. List<object> result = new List<object>();
  1573. string jsonString = "[0, \"Network connnect error\"]";
  1574. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1575. result.Add(channelName);
  1576. if (appSwitch.TraceInfo)
  1577. {
  1578. Trace.WriteLine(string.Format("DateTime {0}, JSON here_now response={1}", DateTime.Now.ToString(), jsonString));
  1579. }
  1580. goToUserCallback<T>(result, usercallback);
  1581. }
  1582. private void detailedHistoryExceptionHandler<T>(string channelName, Action<T> usercallback)
  1583. {
  1584. List<object> result = new List<object>();
  1585. string jsonString = "[0, \"Network connnect error\"]";
  1586. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1587. result.Add(channelName);
  1588. if (appSwitch.TraceInfo)
  1589. {
  1590. Trace.WriteLine(string.Format("DateTime {0}, JSON detailedHistoryExceptionHandler response={1}", DateTime.Now.ToString(), jsonString));
  1591. }
  1592. goToUserCallback<T>(result, usercallback);
  1593. }
  1594. private void timeExceptionHandler<T>(Action<T> usercallback)
  1595. {
  1596. List<object> result = new List<object>();
  1597. string jsonString = "[0, \"Network connnect error\"]";
  1598. result = (List<object>)JsonConvert.DeserializeObject<List<object>>(jsonString);
  1599. if (appSwitch.TraceInfo)
  1600. {
  1601. Trace.WriteLine(string.Format("DateTime {0}, JSON timeExceptionHandler response={1}", DateTime.Now.ToString(), jsonString));
  1602. }
  1603. goToUserCallback<T>(result, usercallback);
  1604. }
  1605. /// <summary>
  1606. /// Gets the result by wrapping the json response based on the request
  1607. /// </summary>
  1608. /// <param name="type"></param>
  1609. /// <param name="jsonString"></param>
  1610. /// <param name="url_components"></param>
  1611. /// <returns></returns>
  1612. private List<object> WrapResultBasedOnResponseType(ResponseType type, string jsonString, List<string> url_components, bool reconnect)
  1613. {
  1614. List<object> result = new List<object>();
  1615. string channelName = getChannelName(url_components, type);
  1616. object objResult = JsonConvert.DeserializeObject<object>(jsonString);
  1617. List<object> result1 = ((IEnumerable)objResult).Cast<object>().ToList();
  1618. if (result1 != null && result1.Count > 0)
  1619. {
  1620. result = decodeMsg(result1, type);
  1621. }
  1622. switch (type)
  1623. {
  1624. case ResponseType.Publish:
  1625. result.Add(channelName);
  1626. _publishMsg.AddOrUpdate(channelName, result, (key, oldValue) => result);
  1627. break;
  1628. case ResponseType.History:
  1629. if (this.CIPHER_KEY.Length > 0)
  1630. {
  1631. List<object> historyDecrypted = new List<object>();
  1632. PubnubCrypto aes = new PubnubCrypto(this.CIPHER_KEY);
  1633. foreach (object message in result)
  1634. {
  1635. historyDecrypted.Add(aes.decrypt(message.ToString()));
  1636. }
  1637. History = historyDecrypted;
  1638. }
  1639. else
  1640. {
  1641. History = result;
  1642. }
  1643. break;
  1644. case ResponseType.DetailedHistory:
  1645. result.Add(channelName);
  1646. break;
  1647. case ResponseType.Here_Now:
  1648. Dictionary<string, object> dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(jsonString);
  1649. result = new List<object>();
  1650. result.Add(dic);
  1651. result.Add(channelName);
  1652. break;
  1653. case ResponseType.Time:
  1654. _Time = result;
  1655. break;
  1656. case ResponseType.Subscribe:
  1657. result.Add(channelName);
  1658. _subscribeMsg.AddOrUpdate(channelName, result, (key, oldValue) =>
  1659. {
  1660. if (reconnect)
  1661. {
  1662. List<object> oldResult = oldValue as List<object>;
  1663. if (oldResult != null)
  1664. {
  1665. result[1] = oldResult[1];
  1666. }
  1667. return result;
  1668. }
  1669. else
  1670. {
  1671. return result;
  1672. }
  1673. });
  1674. break;
  1675. case ResponseType.Presence:
  1676. result.Add(channelName);
  1677. _presenceMsg.AddOrUpdate(channelName, result, (key, oldValue) =>
  1678. {
  1679. if (reconnect)
  1680. {
  1681. List<object> oldResult = oldValue as List<object>;
  1682. if (oldResult != null)
  1683. {
  1684. result[1] = oldResult[1];
  1685. }
  1686. return result;
  1687. }
  1688. else
  1689. {
  1690. return result;
  1691. }
  1692. });
  1693. break;
  1694. case ResponseType.Leave:
  1695. result.Add(channelName);
  1696. break;
  1697. default:
  1698. break;
  1699. };//switch stmt end
  1700. return result;
  1701. }
  1702. private void goToUserCallback<T>(List<object> result, Action<T> usercallback)
  1703. {
  1704. if (usercallback != null)
  1705. {
  1706. if (typeof(T) == typeof(string))
  1707. {
  1708. jsonResponseToUserCallback(result, usercallback);
  1709. }
  1710. else
  1711. {
  1712. usercallback((T)(IList)result.AsReadOnly());
  1713. }
  1714. }
  1715. }
  1716. /// <summary>
  1717. /// Retrieves the channel name from the url components
  1718. /// </summary>
  1719. /// <param name="url_components"></param>
  1720. /// <param name="type"></param>
  1721. /// <returns></returns>
  1722. private string getChannelName(List<string> url_components, ResponseType type)
  1723. {
  1724. string channelName = "";
  1725. switch (type)
  1726. {
  1727. case ResponseType.Subscribe:
  1728. channelName = url_components[2];
  1729. break;
  1730. case ResponseType.Publish:
  1731. channelName = url_components[4];
  1732. break;
  1733. case ResponseType.Presence:
  1734. channelName = url_components[2];
  1735. break;
  1736. case ResponseType.DetailedHistory:
  1737. channelName = url_components[5];
  1738. break;
  1739. case ResponseType.Here_Now:
  1740. channelName = url_components[5];
  1741. break;
  1742. case ResponseType.Leave:
  1743. channelName = url_components[5];
  1744. break;
  1745. default:
  1746. break;
  1747. };
  1748. return channelName;
  1749. }
  1750. // Serialize the given object into JSON string
  1751. public static string SerializeToJsonString(object objectToSerialize)
  1752. {
  1753. return JsonConvert.SerializeObject(objectToSerialize);
  1754. }
  1755. // Deserialize JSON string into List of Objects
  1756. public static List<object> DeserializeToListOfObject(string jsonString)
  1757. {
  1758. using (MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(jsonString)))
  1759. {
  1760. DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(List<object>));
  1761. return (List<object>)serializer.ReadObject(ms);
  1762. }
  1763. }
  1764. private string _encodeURIcomponent(string s, ResponseType type)
  1765. {
  1766. string encodedURI = "";
  1767. StringBuilder o = new StringBuilder();
  1768. foreach (char ch in s.ToCharArray())
  1769. {
  1770. if (isUnsafe(ch))
  1771. {
  1772. o.Append('%');
  1773. o.Append(toHex(ch / 16));
  1774. o.Append(toHex(ch % 16));
  1775. }
  1776. else o.Append(ch);
  1777. }
  1778. encodedURI = o.ToString();
  1779. if (type == ResponseType.Here_Now || type == ResponseType.DetailedHistory || type == ResponseType.Leave)
  1780. {
  1781. encodedURI = encodedURI.Replace("%2F", "%252F");
  1782. }
  1783. return encodedURI;
  1784. }
  1785. private char toHex(int ch)
  1786. {
  1787. return (char)(ch < 10 ? '0' + ch : 'A' + ch - 10);
  1788. }
  1789. private bool isUnsafe(char ch)
  1790. {
  1791. return " ~`!@#$%^&*()+=[]\\{}|;':\",./<>?".IndexOf(ch) >= 0;
  1792. }
  1793. public Guid generateGUID()
  1794. {
  1795. return Guid.NewGuid();
  1796. }
  1797. private static string md5(string text)
  1798. {
  1799. MD5 md5 = new MD5CryptoServiceProvider();
  1800. byte[] data = Encoding.Unicode.GetBytes(text);
  1801. byte[] hash = md5.ComputeHash(data);
  1802. string hexaHash = "";
  1803. foreach (byte b in hash) hexaHash += String.Format("{0:x2}", b);
  1804. return hexaHash;
  1805. }
  1806. public static long translateDateTimeToPubnubUnixNanoSeconds(DateTime dotNetUTCDateTime)
  1807. {
  1808. TimeSpan ts = dotNetUTCDateTime - new DateTime(1970, 1, 1,0,0,0,DateTimeKind.Utc);
  1809. long timestamp = Convert.ToInt64(ts.TotalSeconds) * 10000000;
  1810. return timestamp;
  1811. }
  1812. public static DateTime translatePubnubUnixNanoSecondsToDateTime(long unixNanoSecondTime)
  1813. {
  1814. double timestamp = unixNanoSecondTime / 10000000;
  1815. DateTime dt = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddSeconds(timestamp);
  1816. return dt;
  1817. }
  1818. public static bool IsRunningOnMono()
  1819. {
  1820. return Type.GetType("Mono.Runtime") != null;
  1821. }
  1822. }
  1823. /// <summary>
  1824. /// MD5 Service provider
  1825. /// </summary>
  1826. internal class MD5CryptoServiceProvider : MD5
  1827. {
  1828. public MD5CryptoServiceProvider()
  1829. : base()
  1830. {
  1831. }
  1832. }
  1833. /// <summary>
  1834. /// MD5 messaging-digest algorithm is a widely used cryptographic hash function that produces 128-bit hash value.
  1835. /// </summary>
  1836. internal class MD5 : IDisposable
  1837. {
  1838. static public MD5 Create(string hashName)
  1839. {
  1840. if (hashName == "MD5")
  1841. return new MD5();
  1842. else
  1843. throw new NotSupportedException();
  1844. }
  1845. static public String GetMd5String(String source)
  1846. {
  1847. MD5 md = MD5CryptoServiceProvider.Create();
  1848. byte[] hash;
  1849. //Create a new instance of ASCIIEncoding to
  1850. //convert the string into an array of Unicode bytes.
  1851. UTF8Encoding enc = new UTF8Encoding();
  1852. // ASCIIEncoding enc = new ASCIIEncoding();
  1853. //Convert the string into an array of bytes.
  1854. byte[] buffer = enc.GetBytes(source);
  1855. //Create the hash value from the array of bytes.
  1856. hash = md.ComputeHash(buffer);
  1857. StringBuilder sb = new StringBuilder();
  1858. foreach (byte b in hash)
  1859. sb.Append(b.ToString("x2"));
  1860. return sb.ToString();
  1861. }
  1862. static public MD5 Create()
  1863. {
  1864. return new MD5();
  1865. }
  1866. #region base implementation of the MD5
  1867. #region constants
  1868. private const byte S11 = 7;
  1869. private const byte S12 = 12;
  1870. private const byte S13 = 17;
  1871. private const byte S14 = 22;
  1872. private const byte S21 = 5;
  1873. private const byte S22 = 9;
  1874. private const byte S23 = 14;
  1875. private const byte S24 = 20;
  1876. private const byte S31 = 4;
  1877. private const byte S32 = 11;
  1878. private const byte S33 = 16;
  1879. private const byte S34 = 23;
  1880. private const byte S41 = 6;
  1881. private const byte S42 = 10;
  1882. private const byte S43 = 15;
  1883. private const byte S44 = 21;
  1884. static private byte[] PADDING = new byte[] {
  1885. 0x80, 0, 0, 0, 0, 0,
  1886. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1887. 0, 0, 0, 0, 0, 0, 0,
  1888. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  1889. 0, 0, 0, 0, 0, 0, 0,
  1890. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  1891. };
  1892. #endregion
  1893. #region F, G, H and I are basic MD5 functions.
  1894. static private uint F(uint x, uint y, uint z)
  1895. {
  1896. return (((x) & (y)) | ((~x) & (z)));
  1897. }
  1898. static private uint G(uint x, uint y, uint z)
  1899. {
  1900. return (((x) & (z)) | ((y) & (~z)));
  1901. }
  1902. static private uint H(uint x, uint y, uint z)
  1903. {
  1904. return ((x) ^ (y) ^ (z));
  1905. }
  1906. static private uint I(uint x, uint y, uint z)
  1907. {
  1908. return ((y) ^ ((x) | (~z)));
  1909. }
  1910. #endregion
  1911. #region rotates x left n bits.
  1912. /// <summary>
  1913. /// rotates x left n bits.
  1914. /// </summary>
  1915. /// <param name="x"></param>
  1916. /// <param name="n"></param>
  1917. /// <returns></returns>
  1918. static private uint ROTATE_LEFT(uint x, byte n)
  1919. {
  1920. return (((x) << (n)) | ((x) >> (32 - (n))));
  1921. }
  1922. #endregion
  1923. #region FF, GG, HH, and II transformations
  1924. /// FF, GG, HH, and II transformations
  1925. /// for rounds 1, 2, 3, and 4.
  1926. /// Rotation is separate from addition to prevent re-computation.
  1927. static private void FF(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac)
  1928. {
  1929. (a) += F((b), (c), (d)) + (x) + (uint)(ac);
  1930. (a) = ROTATE_LEFT((a), (s));
  1931. (a) += (b);
  1932. }
  1933. static private void GG(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac)
  1934. {
  1935. (a) += G((b), (c), (d)) + (x) + (uint)(ac);
  1936. (a) = ROTATE_LEFT((a), (s));
  1937. (a) += (b);
  1938. }
  1939. static private void HH(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac)
  1940. {
  1941. (a) += H((b), (c), (d)) + (x) + (uint)(ac);
  1942. (a) = ROTATE_LEFT((a), (s));
  1943. (a) += (b);
  1944. }
  1945. static private void II(ref uint a, uint b, uint c, uint d, uint x, byte s, uint ac)
  1946. {
  1947. (a) += I((b), (c), (d)) + (x) + (uint)(ac);
  1948. (a) = ROTATE_LEFT((a), (s));
  1949. (a) += (b);
  1950. }
  1951. #endregion
  1952. #region context info
  1953. /// <summary>
  1954. /// state (ABCD)
  1955. /// </summary>
  1956. uint[] state = new uint[4];
  1957. /// <summary>
  1958. /// number of bits, modulo 2^64 (LSB first)
  1959. /// </summary>
  1960. uint[] count = new uint[2];
  1961. /// <summary>
  1962. /// input buffer
  1963. /// </summary>
  1964. byte[] buffer = new byte[64];
  1965. #endregion
  1966. internal MD5()
  1967. {
  1968. Initialize();
  1969. }
  1970. /// <summary>
  1971. /// MD5 initialization. Begins an MD5 operation, writing a new context.
  1972. /// </summary>
  1973. /// <remarks>
  1974. /// The RFC named it "MD5Init"
  1975. /// </remarks>
  1976. public virtual void Initialize()
  1977. {
  1978. count[0] = count[1] = 0;
  1979. // Load magic initialization constants.
  1980. state[0] = 0x67452301;
  1981. state[1] = 0xefcdab89;
  1982. state[2] = 0x98badcfe;
  1983. state[3] = 0x10325476;
  1984. }
  1985. /// <summary>
  1986. /// MD5 block update operation. Continues an MD5 message-digest
  1987. /// operation, processing another message block, and updating the
  1988. /// context.
  1989. /// </summary>
  1990. /// <param name="input"></param>
  1991. /// <param name="offset"></param>
  1992. /// <param name="count"></param>
  1993. /// <remarks>The RFC Named it MD5Update</remarks>
  1994. protected virtual void HashCore(byte[] input, int offset, int count)
  1995. {
  1996. int i;
  1997. int index;
  1998. int partLen;
  1999. // Compute number of bytes mod 64
  2000. index = (int)((this.count[0] >> 3) & 0x3F);
  2001. // Update number of bits
  2002. if ((this.count[0] += (uint)((uint)count << 3)) < ((uint)count << 3))
  2003. this.count[1]++;
  2004. this.count[1] += ((uint)count >> 29);
  2005. partLen = 64 - index;
  2006. // Transform as many times as possible.
  2007. if (count >= partLen)
  2008. {
  2009. Buffer.BlockCopy(input, offset, this.buffer, index, partLen);
  2010. Transform(this.buffer, 0);
  2011. for (i = partLen; i + 63 < count; i += 64)
  2012. Transform(input, offset + i);
  2013. index = 0;
  2014. }
  2015. else
  2016. i = 0;
  2017. // Buffer remaining input
  2018. Buffer.BlockCopy(input, offset + i, this.buffer, index, count - i);
  2019. }
  2020. /// <summary>
  2021. /// MD5 finalization. Ends an MD5 message-digest operation, writing the
  2022. /// the message digest and zeroizing the context.
  2023. /// </summary>
  2024. /// <returns>message digest</returns>
  2025. /// <remarks>The RFC named it MD5Final</remarks>
  2026. protected virtual byte[] HashFinal()
  2027. {
  2028. byte[] digest = new byte[16];
  2029. byte[] bits = new byte[8];
  2030. int index, padLen;
  2031. // Save number of bits
  2032. Encode(bits, 0, this.count, 0, 8);
  2033. // Pad out to 56 mod 64.
  2034. index = (int)((uint)(this.count[0] >> 3) & 0x3f);
  2035. padLen = (index < 56) ? (56 - index) : (120 - index);
  2036. HashCore(PADDING, 0, padLen);
  2037. // Append length (before padding)
  2038. HashCore(bits, 0, 8);
  2039. // Store state in digest
  2040. Encode(digest, 0, state, 0, 16);
  2041. // Zeroize sensitive information.
  2042. count[0] = count[1] = 0;
  2043. state[0] = 0;
  2044. state[1] = 0;
  2045. state[2] = 0;
  2046. state[3] = 0;
  2047. // initialize again, to be ready to use
  2048. Initialize();
  2049. return digest;
  2050. }
  2051. /// <summary>
  2052. /// MD5 basic transformation. Transforms state based on 64 bytes block.
  2053. /// </summary>
  2054. /// <param name="block"></param>
  2055. /// <param name="offset"></param>
  2056. private void Transform(byte[] block, int offset)
  2057. {
  2058. uint a = state[0], b = state[1], c = state[2], d = state[3];
  2059. uint[] x = new uint[16];
  2060. Decode(x, 0, block, offset, 64);
  2061. // Round 1
  2062. FF(ref a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */
  2063. FF(ref d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */
  2064. FF(ref c, d, a, b, x[2], S13, 0x242070db); /* 3 */
  2065. FF(ref b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */
  2066. FF(ref a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */
  2067. FF(ref d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */
  2068. FF(ref c, d, a, b, x[6], S13, 0xa8304613); /* 7 */
  2069. FF(ref b, c, d, a, x[7], S14, 0xfd469501); /* 8 */
  2070. FF(ref a, b, c, d, x[8], S11, 0x698098d8); /* 9 */
  2071. FF(ref d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */
  2072. FF(ref c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
  2073. FF(ref b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
  2074. FF(ref a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
  2075. FF(ref d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
  2076. FF(ref c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
  2077. FF(ref b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
  2078. // Round 2
  2079. GG(ref a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */
  2080. GG(ref d, a, b, c, x[6], S22, 0xc040b340); /* 18 */
  2081. GG(ref c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
  2082. GG(ref b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */
  2083. GG(ref a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */
  2084. GG(ref d, a, b, c, x[10], S22, 0x2441453); /* 22 */
  2085. GG(ref c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
  2086. GG(ref b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */
  2087. GG(ref a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */
  2088. GG(ref d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
  2089. GG(ref c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */
  2090. GG(ref b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */
  2091. GG(ref a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
  2092. GG(ref d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */
  2093. GG(ref c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */
  2094. GG(ref b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
  2095. // Round 3
  2096. HH(ref a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */
  2097. HH(ref d, a, b, c, x[8], S32, 0x8771f681); /* 34 */
  2098. HH(ref c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
  2099. HH(ref b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
  2100. HH(ref a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */
  2101. HH(ref d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */
  2102. HH(ref c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */
  2103. HH(ref b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
  2104. HH(ref a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
  2105. HH(ref d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */
  2106. HH(ref c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */
  2107. HH(ref b, c, d, a, x[6], S34, 0x4881d05); /* 44 */
  2108. HH(ref a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */
  2109. HH(ref d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
  2110. HH(ref c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
  2111. HH(ref b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */
  2112. // Round 4
  2113. II(ref a, b, c, d, x[0], S41, 0xf4292244); /* 49 */
  2114. II(ref d, a, b, c, x[7], S42, 0x432aff97); /* 50 */
  2115. II(ref c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
  2116. II(ref b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */
  2117. II(ref a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
  2118. II(ref d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */
  2119. II(ref c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
  2120. II(ref b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */
  2121. II(ref a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */
  2122. II(ref d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
  2123. II(ref c, d, a, b, x[6], S43, 0xa3014314); /* 59 */
  2124. II(ref b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
  2125. II(ref a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */
  2126. II(ref d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
  2127. II(ref c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */
  2128. II(ref b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */
  2129. state[0] += a;
  2130. state[1] += b;
  2131. state[2] += c;
  2132. state[3] += d;
  2133. // Zeroize sensitive information.
  2134. for (int i = 0; i < x.Length; i++)
  2135. x[i] = 0;
  2136. }
  2137. /// <summary>
  2138. /// Encodes input (uint) into output (byte). Assumes len is
  2139. /// multiple of 4.
  2140. /// </summary>
  2141. /// <param name="output"></param>
  2142. /// <param name="outputOffset"></param>
  2143. /// <param name="input"></param>
  2144. /// <param name="inputOffset"></param>
  2145. /// <param name="count"></param>
  2146. private static void Encode(byte[] output, int outputOffset, uint[] input, int inputOffset, int count)
  2147. {
  2148. int i, j;
  2149. int end = outputOffset + count;
  2150. for (i = inputOffset, j = outputOffset; j < end; i++, j += 4)
  2151. {
  2152. output[j] = (byte)(input[i] & 0xff);
  2153. output[j + 1] = (byte)((input[i] >> 8) & 0xff);
  2154. output[j + 2] = (byte)((input[i] >> 16) & 0xff);
  2155. output[j + 3] = (byte)((input[i] >> 24) & 0xff);
  2156. }
  2157. }
  2158. /// <summary>
  2159. /// Decodes input (byte) into output (uint). Assumes len is
  2160. /// a multiple of 4.
  2161. /// </summary>
  2162. /// <param name="output"></param>
  2163. /// <param name="outputOffset"></param>
  2164. /// <param name="input"></param>
  2165. /// <param name="inputOffset"></param>
  2166. /// <param name="count"></param>
  2167. static private void Decode(uint[] output, int outputOffset, byte[] input, int inputOffset, int count)
  2168. {
  2169. int i, j;
  2170. int end = inputOffset + count;
  2171. for (i = outputOffset, j = inputOffset; j < end; i++, j += 4)
  2172. output[i] = ((uint)input[j]) | (((uint)input[j + 1]) << 8) | (((uint)input[j + 2]) << 16) | (((uint)input[j + 3]) <<
  2173. 24);
  2174. }
  2175. #endregion
  2176. #region expose the same interface as the regular MD5 object
  2177. protected byte[] HashValue;
  2178. protected int State;
  2179. public virtual bool CanReuseTransform
  2180. {
  2181. get
  2182. {
  2183. return true;
  2184. }
  2185. }
  2186. public virtual bool CanTransformMultipleBlocks
  2187. {
  2188. get
  2189. {
  2190. return true;
  2191. }
  2192. }
  2193. public virtual byte[] Hash
  2194. {
  2195. get
  2196. {
  2197. if (this.State != 0)
  2198. throw new InvalidOperationException();
  2199. return (byte[])HashValue.Clone();
  2200. }
  2201. }
  2202. public virtual int HashSize
  2203. {
  2204. get
  2205. {
  2206. return HashSizeValue;
  2207. }
  2208. }
  2209. protected int HashSizeValue = 128;
  2210. public virtual int InputBlockSize
  2211. {
  2212. get
  2213. {
  2214. return 1;
  2215. }
  2216. }
  2217. public virtual int OutputBlockSize
  2218. {
  2219. get
  2220. {
  2221. return 1;
  2222. }
  2223. }
  2224. public void Clear()
  2225. {
  2226. Dispose(true);
  2227. }
  2228. public byte[] ComputeHash(byte[] buffer)
  2229. {
  2230. return ComputeHash(buffer, 0, buffer.Length);
  2231. }
  2232. public byte[] ComputeHash(byte[] buffer, int offset, int count)
  2233. {
  2234. Initialize();
  2235. HashCore(buffer, offset, count);
  2236. HashValue = HashFinal();
  2237. return (byte[])HashValue.Clone();
  2238. }
  2239. public byte[] ComputeHash(Stream inputStream)
  2240. {
  2241. Initialize();
  2242. int count;
  2243. byte[] buffer = new byte[4096];
  2244. while (0 < (count = inputStream.Read(buffer, 0, 4096)))
  2245. {
  2246. HashCore(buffer, 0, count);
  2247. }
  2248. HashValue = HashFinal();
  2249. return (byte[])HashValue.Clone();
  2250. }
  2251. public int TransformBlock(
  2252. byte[] inputBuffer,
  2253. int inputOffset,
  2254. int inputCount,
  2255. byte[] outputBuffer,
  2256. int outputOffset
  2257. )
  2258. {
  2259. if (inputBuffer == null)
  2260. {
  2261. throw new ArgumentNullException("inputBuffer");
  2262. }
  2263. if (inputOffset < 0)
  2264. {
  2265. throw new ArgumentOutOfRangeException("inputOffset");
  2266. }
  2267. if ((inputCount < 0) || (inputCount > inputBuffer.Length))
  2268. {
  2269. throw new ArgumentException("inputCount");
  2270. }
  2271. if ((inputBuffer.Length - inputCount) < inputOffset)
  2272. {
  2273. throw new ArgumentOutOfRangeException("inputOffset");
  2274. }
  2275. if (this.State == 0)
  2276. {
  2277. Initialize();
  2278. this.State = 1;
  2279. }
  2280. HashCore(inputBuffer, inputOffset, inputCount);
  2281. if ((inputBuffer != outputBuffer) || (inputOffset != outputOffset))
  2282. {
  2283. Buffer.BlockCopy(inputBuffer, inputOffset, outputBuffer, outputOffset, inputCount);
  2284. }
  2285. return inputCount;
  2286. }
  2287. public byte[] TransformFinalBlock(
  2288. byte[] inputBuffer,
  2289. int inputOffset,
  2290. int inputCount
  2291. )
  2292. {
  2293. if (inputBuffer == null)
  2294. {
  2295. throw new ArgumentNullException("inputBuffer");
  2296. }
  2297. if (inputOffset < 0)
  2298. {
  2299. throw new ArgumentOutOfRangeException("inputOffset");
  2300. }
  2301. if ((inputCount < 0) || (inputCount > inputBuffer.Length))
  2302. {
  2303. throw new ArgumentException("inputCount");
  2304. }
  2305. if ((inputBuffer.Length - inputCount) < inputOffset)
  2306. {
  2307. throw new ArgumentOutOfRangeException("inputOffset");
  2308. }
  2309. if (this.State == 0)
  2310. {
  2311. Initialize();
  2312. }
  2313. HashCore(inputBuffer, inputOffset, inputCount);
  2314. HashValue = HashFinal();
  2315. byte[] buffer = new byte[inputCount];
  2316. Buffer.BlockCopy(inputBuffer, inputOffset, buffer, 0, inputCount);
  2317. this.State = 0;
  2318. return buffer;
  2319. }
  2320. #endregion
  2321. protected virtual void Dispose(bool disposing)
  2322. {
  2323. if (!disposing)
  2324. Initialize();
  2325. }
  2326. public void Dispose()
  2327. {
  2328. Dispose(true);
  2329. }
  2330. }
  2331. public class PubnubCrypto
  2332. {
  2333. private string CIPHER_KEY = "";
  2334. public PubnubCrypto(string cipher_key)
  2335. {
  2336. this.CIPHER_KEY = cipher_key;
  2337. }
  2338. /// <summary>
  2339. /// Computes the hash using the specified algo
  2340. /// </summary>
  2341. /// <returns>
  2342. /// The hash.
  2343. /// </returns>
  2344. /// <param name='input'>
  2345. /// Input string
  2346. /// </param>
  2347. /// <param name='algorithm'>
  2348. /// Algorithm to use for Hashing
  2349. /// </param>
  2350. private static string ComputeHash(string input, HashAlgorithm algorithm)
  2351. {
  2352. Byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);
  2353. Byte[] hashedBytes = algorithm.ComputeHash(inputBytes);
  2354. return BitConverter.ToString(hashedBytes);
  2355. }
  2356. private string GetEncryptionKey()
  2357. {
  2358. //Compute Hash using the SHA256
  2359. string strKeySHA256HashRaw = ComputeHash(this.CIPHER_KEY, new SHA256CryptoServiceProvider());
  2360. //delete the "-" that appear after every 2 chars
  2361. string strKeySHA256Hash = (strKeySHA256HashRaw.Replace("-", "")).Substring(0, 32);
  2362. //convert to lower case
  2363. return strKeySHA256Hash.ToLower();
  2364. }
  2365. /**
  2366. * EncryptOrDecrypt
  2367. *
  2368. * Basic function for encrypt or decrypt a string
  2369. * for encrypt type = true
  2370. * for decrypt type = false
  2371. */
  2372. private string EncryptOrDecrypt(bool type, string plainStr)
  2373. {
  2374. RijndaelManaged aesEncryption = new RijndaelManaged();
  2375. aesEncryption.KeySize = 256;
  2376. aesEncryption.BlockSize = 128;
  2377. //Mode CBC
  2378. aesEncryption.Mode = CipherMode.CBC;
  2379. //padding
  2380. aesEncryption.Padding = PaddingMode.PKCS7;
  2381. //get ASCII bytes of the string
  2382. aesEncryption.IV = System.Text.Encoding.ASCII.GetBytes("0123456789012345");
  2383. aesEncryption.Key = System.Text.Encoding.ASCII.GetBytes(GetEncryptionKey());
  2384. if (type)
  2385. {
  2386. ICryptoTransform crypto = aesEncryption.CreateEncryptor();
  2387. plainStr = EncodeNonAsciiCharacters(plainStr);
  2388. byte[] plainText = Encoding.ASCII.GetBytes(plainStr);
  2389. //encrypt
  2390. byte[] cipherText = crypto.TransformFinalBlock(plainText, 0, plainText.Length);
  2391. return Convert.ToBase64String(cipherText);
  2392. }
  2393. else
  2394. {
  2395. try
  2396. {
  2397. ICryptoTransform decrypto = aesEncryption.CreateDecryptor();
  2398. //decode
  2399. byte[] decryptedBytes = Convert.FromBase64CharArray(plainStr.ToCharArray(), 0, plainStr.Length);
  2400. //decrypt
  2401. string strDecrypted = System.Text.Encoding.ASCII.GetString(decrypto.TransformFinalBlock(decryptedBytes, 0, decryptedBytes.Length));
  2402. return strDecrypted;
  2403. }
  2404. catch
  2405. {
  2406. return "**DECRYPT ERROR**";
  2407. }
  2408. }
  2409. }
  2410. // encrypt string
  2411. public string encrypt(string plainStr)
  2412. {
  2413. if (plainStr == null || plainStr.Length <= 0) throw new ArgumentNullException("plainStr");
  2414. return EncryptOrDecrypt(true, plainStr);
  2415. }
  2416. // decrypt string
  2417. public string decrypt(string cipherStr)
  2418. {
  2419. if (cipherStr == null) throw new ArgumentNullException("cipherStr");
  2420. return EncryptOrDecrypt(false, cipherStr);
  2421. }
  2422. //md5 used for AES encryption key
  2423. private static byte[] md5(string cipher_key)
  2424. {
  2425. MD5 obj = new MD5CryptoServiceProvider();
  2426. byte[] data = Encoding.Default.GetBytes(cipher_key);
  2427. return obj.ComputeHash(data);
  2428. }
  2429. /// <summary>
  2430. /// Encodes the non ASCII characters.
  2431. /// </summary>
  2432. /// <returns>
  2433. /// The non ASCII characters.
  2434. /// </returns>
  2435. /// <param name='value'>
  2436. /// Value.
  2437. /// </param>
  2438. private string EncodeNonAsciiCharacters(string value)
  2439. {
  2440. StringBuilder sb = new StringBuilder();
  2441. foreach (char c in value)
  2442. {
  2443. if (c > 127)
  2444. {
  2445. // This character is too big for ASCII
  2446. string encodedValue = "\\u" + ((int)c).ToString("x4");
  2447. sb.Append(encodedValue);
  2448. }
  2449. else
  2450. {
  2451. sb.Append(c);
  2452. }
  2453. }
  2454. return sb.ToString();
  2455. }
  2456. }
  2457. internal enum ResponseType
  2458. {
  2459. Publish,
  2460. History,
  2461. Time,
  2462. Subscribe,
  2463. Presence,
  2464. Here_Now,
  2465. DetailedHistory,
  2466. Leave
  2467. }
  2468. internal class ReconnectState<T>
  2469. {
  2470. public string channel;
  2471. public ResponseType type;
  2472. public Action<T> callback;
  2473. public object timetoken;
  2474. public ReconnectState()
  2475. {
  2476. channel = "";
  2477. callback = null;
  2478. timetoken = null;
  2479. }
  2480. }
  2481. internal class RequestState
  2482. {
  2483. public HttpWebRequest request;
  2484. public HttpWebResponse response;
  2485. public ResponseType type;
  2486. public string channel;
  2487. public RequestState()
  2488. {
  2489. request = null;
  2490. response = null;
  2491. channel = "";
  2492. }
  2493. }
  2494. internal class InternetState
  2495. {
  2496. public Action<bool> callback;
  2497. public IPAddress ipaddr;
  2498. public InternetState()
  2499. {
  2500. callback = null;
  2501. ipaddr = null;
  2502. }
  2503. }
  2504. internal class ClientNetworkStatus
  2505. {
  2506. private static bool _status = true;
  2507. private static TraceSwitch appSwitch = new TraceSwitch("PubnubTraceSwitch", "Pubnub Trace Switch in config file");
  2508. private static ManualResetEventSlim mres = new ManualResetEventSlim(false);
  2509. internal static void checkInternetStatus(bool systemActive, Action<bool> callback)
  2510. {
  2511. if (callback != null)
  2512. {
  2513. try
  2514. {
  2515. if (systemActive)
  2516. {
  2517. checkClientNetworkAvailability(callback);
  2518. }
  2519. else
  2520. {
  2521. callback(false);
  2522. }
  2523. }
  2524. catch (Exception ex)
  2525. {
  2526. if (appSwitch.TraceError)
  2527. {
  2528. Trace.WriteLine(string.Format("DateTime {0} checkInternetStatus Error. {1}", DateTime.Now.ToString(), ex.ToString()));
  2529. }
  2530. }
  2531. }
  2532. }
  2533. internal static bool checkInternetStatus(bool systemActive)
  2534. {
  2535. checkClientNetworkAvailability(callbackClientNetworkStatus);
  2536. return _status;
  2537. }
  2538. private static void callbackClientNetworkStatus(bool status)
  2539. {
  2540. _status = status;
  2541. }
  2542. private static void checkClientNetworkAvailability(Action<bool> callback)
  2543. {
  2544. if (NetworkInterface.GetIsNetworkAvailable())
  2545. {
  2546. NetworkInterface[] netInterfaces = NetworkInterface.GetAllNetworkInterfaces();
  2547. foreach (NetworkInterface netInterface in netInterfaces)
  2548. {
  2549. IPInterfaceProperties ip = netInterface.GetIPProperties();
  2550. if (netInterface.OperationalStatus == OperationalStatus.Up)
  2551. {
  2552. if (netInterface.NetworkInterfaceType != NetworkInterfaceType.Tunnel
  2553. && netInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback)
  2554. {
  2555. IPInterfaceProperties prop = netInterface.GetIPProperties();
  2556. UnicastIPAddressInformationCollection unicast = prop.UnicastAddresses;
  2557. foreach (UnicastIPAddressInformation uniIP in unicast)
  2558. {
  2559. IPAddress addrip = uniIP.Address;
  2560. if (addrip.AddressFamily != AddressFamily.InterNetwork) continue;
  2561. InternetState state = new InternetState();
  2562. state.ipaddr = addrip;
  2563. state.callback = callback;
  2564. ThreadPool.QueueUserWorkItem(checkSocketConnect, state);
  2565. mres.Wait();
  2566. }
  2567. }
  2568. }
  2569. }
  2570. }
  2571. else
  2572. {
  2573. callback(false);
  2574. }
  2575. }
  2576. private static void checkSocketConnect(object internetState)
  2577. {
  2578. bool connected = false;
  2579. InternetState state = internetState as InternetState;
  2580. IPAddress ipaddr = state.ipaddr;
  2581. Action<bool> callback = state.callback;
  2582. try
  2583. {
  2584. using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
  2585. {
  2586. socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, false);
  2587. IPEndPoint local = new IPEndPoint(ipaddr, 0);
  2588. socket.Bind(local);
  2589. socket.Connect("pubsub.pubnub.com", 80);
  2590. connected = true;
  2591. socket.Shutdown(SocketShutdown.Both);
  2592. socket.Disconnect(true);
  2593. socket.Close();
  2594. }
  2595. }
  2596. catch (ObjectDisposedException objEx)
  2597. {
  2598. if (appSwitch.TraceVerbose)
  2599. {
  2600. Trace.WriteLine(string.Format("DateTime {0} checkSocketConnect Error. {1}", DateTime.Now.ToString(), objEx.ToString()));
  2601. }
  2602. }
  2603. catch (Exception ex)
  2604. {
  2605. if (appSwitch.TraceVerbose)
  2606. {
  2607. Trace.WriteLine(string.Format("DateTime {0} checkSocketConnect Error. {1}", DateTime.Now.ToString(), ex.ToString()));
  2608. }
  2609. }
  2610. if (callback != null)
  2611. {
  2612. callback(connected);
  2613. }
  2614. mres.Set();
  2615. }
  2616. }
  2617. }